PageRenderTime 235ms CodeModel.GetById 146ms app.highlight 76ms RepoModel.GetById 1ms app.codeStats 1ms

/src/freetype/src/bdf/bdflib.c

https://bitbucket.org/cabalistic/ogredeps/
C | 2613 lines | 1817 code | 526 blank | 270 comment | 454 complexity | 6e31146d0142cd3803006e5f21d225c8 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*
   2 * Copyright 2000 Computing Research Labs, New Mexico State University
   3 * Copyright 2001-2012
   4 *   Francesco Zappa Nardelli
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a
   7 * copy of this software and associated documentation files (the "Software"),
   8 * to deal in the Software without restriction, including without limitation
   9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10 * and/or sell copies of the Software, and to permit persons to whom the
  11 * Software is furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  19 * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
  20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
  21 * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
  22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23 */
  24
  25  /*************************************************************************/
  26  /*                                                                       */
  27  /*  This file is based on bdf.c,v 1.22 2000/03/16 20:08:50               */
  28  /*                                                                       */
  29  /*  taken from Mark Leisher's xmbdfed package                            */
  30  /*                                                                       */
  31  /*************************************************************************/
  32
  33
  34#include <ft2build.h>
  35
  36#include FT_FREETYPE_H
  37#include FT_INTERNAL_DEBUG_H
  38#include FT_INTERNAL_STREAM_H
  39#include FT_INTERNAL_OBJECTS_H
  40
  41#include "bdf.h"
  42#include "bdferror.h"
  43
  44
  45  /*************************************************************************/
  46  /*                                                                       */
  47  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
  48  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
  49  /* messages during execution.                                            */
  50  /*                                                                       */
  51#undef  FT_COMPONENT
  52#define FT_COMPONENT  trace_bdflib
  53
  54
  55  /*************************************************************************/
  56  /*                                                                       */
  57  /* Default BDF font options.                                             */
  58  /*                                                                       */
  59  /*************************************************************************/
  60
  61
  62  static const bdf_options_t  _bdf_opts =
  63  {
  64    1,                /* Correct metrics.               */
  65    1,                /* Preserve unencoded glyphs.     */
  66    0,                /* Preserve comments.             */
  67    BDF_PROPORTIONAL  /* Default spacing.               */
  68  };
  69
  70
  71  /*************************************************************************/
  72  /*                                                                       */
  73  /* Builtin BDF font properties.                                          */
  74  /*                                                                       */
  75  /*************************************************************************/
  76
  77  /* List of most properties that might appear in a font.  Doesn't include */
  78  /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts.           */
  79
  80  static const bdf_property_t  _bdf_properties[] =
  81  {
  82    { (char *)"ADD_STYLE_NAME",          BDF_ATOM,     1, { 0 } },
  83    { (char *)"AVERAGE_WIDTH",           BDF_INTEGER,  1, { 0 } },
  84    { (char *)"AVG_CAPITAL_WIDTH",       BDF_INTEGER,  1, { 0 } },
  85    { (char *)"AVG_LOWERCASE_WIDTH",     BDF_INTEGER,  1, { 0 } },
  86    { (char *)"CAP_HEIGHT",              BDF_INTEGER,  1, { 0 } },
  87    { (char *)"CHARSET_COLLECTIONS",     BDF_ATOM,     1, { 0 } },
  88    { (char *)"CHARSET_ENCODING",        BDF_ATOM,     1, { 0 } },
  89    { (char *)"CHARSET_REGISTRY",        BDF_ATOM,     1, { 0 } },
  90    { (char *)"COMMENT",                 BDF_ATOM,     1, { 0 } },
  91    { (char *)"COPYRIGHT",               BDF_ATOM,     1, { 0 } },
  92    { (char *)"DEFAULT_CHAR",            BDF_CARDINAL, 1, { 0 } },
  93    { (char *)"DESTINATION",             BDF_CARDINAL, 1, { 0 } },
  94    { (char *)"DEVICE_FONT_NAME",        BDF_ATOM,     1, { 0 } },
  95    { (char *)"END_SPACE",               BDF_INTEGER,  1, { 0 } },
  96    { (char *)"FACE_NAME",               BDF_ATOM,     1, { 0 } },
  97    { (char *)"FAMILY_NAME",             BDF_ATOM,     1, { 0 } },
  98    { (char *)"FIGURE_WIDTH",            BDF_INTEGER,  1, { 0 } },
  99    { (char *)"FONT",                    BDF_ATOM,     1, { 0 } },
 100    { (char *)"FONTNAME_REGISTRY",       BDF_ATOM,     1, { 0 } },
 101    { (char *)"FONT_ASCENT",             BDF_INTEGER,  1, { 0 } },
 102    { (char *)"FONT_DESCENT",            BDF_INTEGER,  1, { 0 } },
 103    { (char *)"FOUNDRY",                 BDF_ATOM,     1, { 0 } },
 104    { (char *)"FULL_NAME",               BDF_ATOM,     1, { 0 } },
 105    { (char *)"ITALIC_ANGLE",            BDF_INTEGER,  1, { 0 } },
 106    { (char *)"MAX_SPACE",               BDF_INTEGER,  1, { 0 } },
 107    { (char *)"MIN_SPACE",               BDF_INTEGER,  1, { 0 } },
 108    { (char *)"NORM_SPACE",              BDF_INTEGER,  1, { 0 } },
 109    { (char *)"NOTICE",                  BDF_ATOM,     1, { 0 } },
 110    { (char *)"PIXEL_SIZE",              BDF_INTEGER,  1, { 0 } },
 111    { (char *)"POINT_SIZE",              BDF_INTEGER,  1, { 0 } },
 112    { (char *)"QUAD_WIDTH",              BDF_INTEGER,  1, { 0 } },
 113    { (char *)"RAW_ASCENT",              BDF_INTEGER,  1, { 0 } },
 114    { (char *)"RAW_AVERAGE_WIDTH",       BDF_INTEGER,  1, { 0 } },
 115    { (char *)"RAW_AVG_CAPITAL_WIDTH",   BDF_INTEGER,  1, { 0 } },
 116    { (char *)"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER,  1, { 0 } },
 117    { (char *)"RAW_CAP_HEIGHT",          BDF_INTEGER,  1, { 0 } },
 118    { (char *)"RAW_DESCENT",             BDF_INTEGER,  1, { 0 } },
 119    { (char *)"RAW_END_SPACE",           BDF_INTEGER,  1, { 0 } },
 120    { (char *)"RAW_FIGURE_WIDTH",        BDF_INTEGER,  1, { 0 } },
 121    { (char *)"RAW_MAX_SPACE",           BDF_INTEGER,  1, { 0 } },
 122    { (char *)"RAW_MIN_SPACE",           BDF_INTEGER,  1, { 0 } },
 123    { (char *)"RAW_NORM_SPACE",          BDF_INTEGER,  1, { 0 } },
 124    { (char *)"RAW_PIXEL_SIZE",          BDF_INTEGER,  1, { 0 } },
 125    { (char *)"RAW_POINT_SIZE",          BDF_INTEGER,  1, { 0 } },
 126    { (char *)"RAW_PIXELSIZE",           BDF_INTEGER,  1, { 0 } },
 127    { (char *)"RAW_POINTSIZE",           BDF_INTEGER,  1, { 0 } },
 128    { (char *)"RAW_QUAD_WIDTH",          BDF_INTEGER,  1, { 0 } },
 129    { (char *)"RAW_SMALL_CAP_SIZE",      BDF_INTEGER,  1, { 0 } },
 130    { (char *)"RAW_STRIKEOUT_ASCENT",    BDF_INTEGER,  1, { 0 } },
 131    { (char *)"RAW_STRIKEOUT_DESCENT",   BDF_INTEGER,  1, { 0 } },
 132    { (char *)"RAW_SUBSCRIPT_SIZE",      BDF_INTEGER,  1, { 0 } },
 133    { (char *)"RAW_SUBSCRIPT_X",         BDF_INTEGER,  1, { 0 } },
 134    { (char *)"RAW_SUBSCRIPT_Y",         BDF_INTEGER,  1, { 0 } },
 135    { (char *)"RAW_SUPERSCRIPT_SIZE",    BDF_INTEGER,  1, { 0 } },
 136    { (char *)"RAW_SUPERSCRIPT_X",       BDF_INTEGER,  1, { 0 } },
 137    { (char *)"RAW_SUPERSCRIPT_Y",       BDF_INTEGER,  1, { 0 } },
 138    { (char *)"RAW_UNDERLINE_POSITION",  BDF_INTEGER,  1, { 0 } },
 139    { (char *)"RAW_UNDERLINE_THICKNESS", BDF_INTEGER,  1, { 0 } },
 140    { (char *)"RAW_X_HEIGHT",            BDF_INTEGER,  1, { 0 } },
 141    { (char *)"RELATIVE_SETWIDTH",       BDF_CARDINAL, 1, { 0 } },
 142    { (char *)"RELATIVE_WEIGHT",         BDF_CARDINAL, 1, { 0 } },
 143    { (char *)"RESOLUTION",              BDF_INTEGER,  1, { 0 } },
 144    { (char *)"RESOLUTION_X",            BDF_CARDINAL, 1, { 0 } },
 145    { (char *)"RESOLUTION_Y",            BDF_CARDINAL, 1, { 0 } },
 146    { (char *)"SETWIDTH_NAME",           BDF_ATOM,     1, { 0 } },
 147    { (char *)"SLANT",                   BDF_ATOM,     1, { 0 } },
 148    { (char *)"SMALL_CAP_SIZE",          BDF_INTEGER,  1, { 0 } },
 149    { (char *)"SPACING",                 BDF_ATOM,     1, { 0 } },
 150    { (char *)"STRIKEOUT_ASCENT",        BDF_INTEGER,  1, { 0 } },
 151    { (char *)"STRIKEOUT_DESCENT",       BDF_INTEGER,  1, { 0 } },
 152    { (char *)"SUBSCRIPT_SIZE",          BDF_INTEGER,  1, { 0 } },
 153    { (char *)"SUBSCRIPT_X",             BDF_INTEGER,  1, { 0 } },
 154    { (char *)"SUBSCRIPT_Y",             BDF_INTEGER,  1, { 0 } },
 155    { (char *)"SUPERSCRIPT_SIZE",        BDF_INTEGER,  1, { 0 } },
 156    { (char *)"SUPERSCRIPT_X",           BDF_INTEGER,  1, { 0 } },
 157    { (char *)"SUPERSCRIPT_Y",           BDF_INTEGER,  1, { 0 } },
 158    { (char *)"UNDERLINE_POSITION",      BDF_INTEGER,  1, { 0 } },
 159    { (char *)"UNDERLINE_THICKNESS",     BDF_INTEGER,  1, { 0 } },
 160    { (char *)"WEIGHT",                  BDF_CARDINAL, 1, { 0 } },
 161    { (char *)"WEIGHT_NAME",             BDF_ATOM,     1, { 0 } },
 162    { (char *)"X_HEIGHT",                BDF_INTEGER,  1, { 0 } },
 163    { (char *)"_MULE_BASELINE_OFFSET",   BDF_INTEGER,  1, { 0 } },
 164    { (char *)"_MULE_RELATIVE_COMPOSE",  BDF_INTEGER,  1, { 0 } },
 165  };
 166
 167  static const unsigned long
 168  _num_bdf_properties = sizeof ( _bdf_properties ) /
 169                        sizeof ( _bdf_properties[0] );
 170
 171
 172  /* Auto correction messages. */
 173#define ACMSG1   "FONT_ASCENT property missing.  " \
 174                 "Added `FONT_ASCENT %hd'.\n"
 175#define ACMSG2   "FONT_DESCENT property missing.  " \
 176                 "Added `FONT_DESCENT %hd'.\n"
 177#define ACMSG3   "Font width != actual width.  Old: %hd New: %hd.\n"
 178#define ACMSG4   "Font left bearing != actual left bearing.  " \
 179                 "Old: %hd New: %hd.\n"
 180#define ACMSG5   "Font ascent != actual ascent.  Old: %hd New: %hd.\n"
 181#define ACMSG6   "Font descent != actual descent.  Old: %hd New: %hd.\n"
 182#define ACMSG7   "Font height != actual height. Old: %hd New: %hd.\n"
 183#define ACMSG8   "Glyph scalable width (SWIDTH) adjustments made.\n"
 184#define ACMSG9   "SWIDTH field missing at line %ld.  Set automatically.\n"
 185#define ACMSG10  "DWIDTH field missing at line %ld.  Set to glyph width.\n"
 186#define ACMSG11  "SIZE bits per pixel field adjusted to %hd.\n"
 187#define ACMSG12  "Duplicate encoding %ld (%s) changed to unencoded.\n"
 188#define ACMSG13  "Glyph %ld extra rows removed.\n"
 189#define ACMSG14  "Glyph %ld extra columns removed.\n"
 190#define ACMSG15  "Incorrect glyph count: %ld indicated but %ld found.\n"
 191#define ACMSG16  "Glyph %ld missing columns padded with zero bits.\n"
 192
 193  /* Error messages. */
 194#define ERRMSG1  "[line %ld] Missing `%s' line.\n"
 195#define ERRMSG2  "[line %ld] Font header corrupted or missing fields.\n"
 196#define ERRMSG3  "[line %ld] Font glyphs corrupted or missing fields.\n"
 197#define ERRMSG4  "[line %ld] BBX too big.\n"
 198#define ERRMSG5  "[line %ld] `%s' value too big.\n"
 199#define ERRMSG6  "[line %ld] Input line too long.\n"
 200#define ERRMSG7  "[line %ld] Font name too long.\n"
 201#define ERRMSG8  "[line %ld] Invalid `%s' value.\n"
 202#define ERRMSG9  "[line %ld] Invalid keyword.\n"
 203
 204  /* Debug messages. */
 205#define DBGMSG1  "  [%6ld] %s" /* no \n */
 206#define DBGMSG2  " (0x%lX)\n"
 207
 208
 209  /*************************************************************************/
 210  /*                                                                       */
 211  /* Hash table utilities for the properties.                              */
 212  /*                                                                       */
 213  /*************************************************************************/
 214
 215  /* XXX: Replace this with FreeType's hash functions */
 216
 217
 218#define INITIAL_HT_SIZE  241
 219
 220  typedef void
 221  (*hash_free_func)( hashnode  node );
 222
 223  static hashnode*
 224  hash_bucket( const char*  key,
 225               hashtable*   ht )
 226  {
 227    const char*    kp  = key;
 228    unsigned long  res = 0;
 229    hashnode*      bp  = ht->table, *ndp;
 230
 231
 232    /* Mocklisp hash function. */
 233    while ( *kp )
 234      res = ( res << 5 ) - res + *kp++;
 235
 236    ndp = bp + ( res % ht->size );
 237    while ( *ndp )
 238    {
 239      kp = (*ndp)->key;
 240      if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 )
 241        break;
 242      ndp--;
 243      if ( ndp < bp )
 244        ndp = bp + ( ht->size - 1 );
 245    }
 246
 247    return ndp;
 248  }
 249
 250
 251  static FT_Error
 252  hash_rehash( hashtable*  ht,
 253               FT_Memory   memory )
 254  {
 255    hashnode*  obp = ht->table, *bp, *nbp;
 256    int        i, sz = ht->size;
 257    FT_Error   error = BDF_Err_Ok;
 258
 259
 260    ht->size <<= 1;
 261    ht->limit  = ht->size / 3;
 262
 263    if ( FT_NEW_ARRAY( ht->table, ht->size ) )
 264      goto Exit;
 265
 266    for ( i = 0, bp = obp; i < sz; i++, bp++ )
 267    {
 268      if ( *bp )
 269      {
 270        nbp = hash_bucket( (*bp)->key, ht );
 271        *nbp = *bp;
 272      }
 273    }
 274    FT_FREE( obp );
 275
 276  Exit:
 277    return error;
 278  }
 279
 280
 281  static FT_Error
 282  hash_init( hashtable*  ht,
 283             FT_Memory   memory )
 284  {
 285    int       sz = INITIAL_HT_SIZE;
 286    FT_Error  error = BDF_Err_Ok;
 287
 288
 289    ht->size  = sz;
 290    ht->limit = sz / 3;
 291    ht->used  = 0;
 292
 293    if ( FT_NEW_ARRAY( ht->table, sz ) )
 294      goto Exit;
 295
 296  Exit:
 297    return error;
 298  }
 299
 300
 301  static void
 302  hash_free( hashtable*  ht,
 303             FT_Memory   memory )
 304  {
 305    if ( ht != 0 )
 306    {
 307      int        i, sz = ht->size;
 308      hashnode*  bp = ht->table;
 309
 310
 311      for ( i = 0; i < sz; i++, bp++ )
 312        FT_FREE( *bp );
 313
 314      FT_FREE( ht->table );
 315    }
 316  }
 317
 318
 319  static FT_Error
 320  hash_insert( char*       key,
 321               size_t      data,
 322               hashtable*  ht,
 323               FT_Memory   memory )
 324  {
 325    hashnode  nn, *bp = hash_bucket( key, ht );
 326    FT_Error  error = BDF_Err_Ok;
 327
 328
 329    nn = *bp;
 330    if ( !nn )
 331    {
 332      if ( FT_NEW( nn ) )
 333        goto Exit;
 334      *bp = nn;
 335
 336      nn->key  = key;
 337      nn->data = data;
 338
 339      if ( ht->used >= ht->limit )
 340      {
 341        error = hash_rehash( ht, memory );
 342        if ( error )
 343          goto Exit;
 344      }
 345      ht->used++;
 346    }
 347    else
 348      nn->data = data;
 349
 350  Exit:
 351    return error;
 352  }
 353
 354
 355  static hashnode
 356  hash_lookup( const char* key,
 357               hashtable*  ht )
 358  {
 359    hashnode *np = hash_bucket( key, ht );
 360
 361
 362    return *np;
 363  }
 364
 365
 366  /*************************************************************************/
 367  /*                                                                       */
 368  /* Utility types and functions.                                          */
 369  /*                                                                       */
 370  /*************************************************************************/
 371
 372
 373  /* Function type for parsing lines of a BDF font. */
 374
 375  typedef FT_Error
 376  (*_bdf_line_func_t)( char*          line,
 377                       unsigned long  linelen,
 378                       unsigned long  lineno,
 379                       void*          call_data,
 380                       void*          client_data );
 381
 382
 383  /* List structure for splitting lines into fields. */
 384
 385  typedef struct  _bdf_list_t_
 386  {
 387    char**         field;
 388    unsigned long  size;
 389    unsigned long  used;
 390    FT_Memory      memory;
 391
 392  } _bdf_list_t;
 393
 394
 395  /* Structure used while loading BDF fonts. */
 396
 397  typedef struct  _bdf_parse_t_
 398  {
 399    unsigned long   flags;
 400    unsigned long   cnt;
 401    unsigned long   row;
 402
 403    short           minlb;
 404    short           maxlb;
 405    short           maxrb;
 406    short           maxas;
 407    short           maxds;
 408
 409    short           rbearing;
 410
 411    char*           glyph_name;
 412    long            glyph_enc;
 413
 414    bdf_font_t*     font;
 415    bdf_options_t*  opts;
 416
 417    unsigned long   have[34816]; /* must be in sync with `nmod' and `umod' */
 418                                 /* arrays from `bdf_font_t' structure     */
 419    _bdf_list_t     list;
 420
 421    FT_Memory       memory;
 422
 423  } _bdf_parse_t;
 424
 425
 426#define setsbit( m, cc ) \
 427          ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
 428#define sbitset( m, cc ) \
 429          ( m[(FT_Byte)(cc) >> 3]  & ( 1 << ( (cc) & 7 ) ) )
 430
 431
 432  static void
 433  _bdf_list_init( _bdf_list_t*  list,
 434                  FT_Memory     memory )
 435  {
 436    FT_ZERO( list );
 437    list->memory = memory;
 438  }
 439
 440
 441  static void
 442  _bdf_list_done( _bdf_list_t*  list )
 443  {
 444    FT_Memory  memory = list->memory;
 445
 446
 447    if ( memory )
 448    {
 449      FT_FREE( list->field );
 450      FT_ZERO( list );
 451    }
 452  }
 453
 454
 455  static FT_Error
 456  _bdf_list_ensure( _bdf_list_t*   list,
 457                    unsigned long  num_items ) /* same as _bdf_list_t.used */
 458  {
 459    FT_Error  error = BDF_Err_Ok;
 460
 461
 462    if ( num_items > list->size )
 463    {
 464      unsigned long  oldsize = list->size; /* same as _bdf_list_t.size */
 465      unsigned long  newsize = oldsize + ( oldsize >> 1 ) + 5;
 466      unsigned long  bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) );
 467      FT_Memory      memory  = list->memory;
 468
 469
 470      if ( oldsize == bigsize )
 471      {
 472        error = BDF_Err_Out_Of_Memory;
 473        goto Exit;
 474      }
 475      else if ( newsize < oldsize || newsize > bigsize )
 476        newsize = bigsize;
 477
 478      if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) )
 479        goto Exit;
 480
 481      list->size = newsize;
 482    }
 483
 484  Exit:
 485    return error;
 486  }
 487
 488
 489  static void
 490  _bdf_list_shift( _bdf_list_t*   list,
 491                   unsigned long  n )
 492  {
 493    unsigned long  i, u;
 494
 495
 496    if ( list == 0 || list->used == 0 || n == 0 )
 497      return;
 498
 499    if ( n >= list->used )
 500    {
 501      list->used = 0;
 502      return;
 503    }
 504
 505    for ( u = n, i = 0; u < list->used; i++, u++ )
 506      list->field[i] = list->field[u];
 507    list->used -= n;
 508  }
 509
 510
 511  /* An empty string for empty fields. */
 512
 513  static const char  empty[1] = { 0 };      /* XXX eliminate this */
 514
 515
 516  static char *
 517  _bdf_list_join( _bdf_list_t*    list,
 518                  int             c,
 519                  unsigned long  *alen )
 520  {
 521    unsigned long  i, j;
 522    char           *fp, *dp;
 523
 524
 525    *alen = 0;
 526
 527    if ( list == 0 || list->used == 0 )
 528      return 0;
 529
 530    dp = list->field[0];
 531    for ( i = j = 0; i < list->used; i++ )
 532    {
 533      fp = list->field[i];
 534      while ( *fp )
 535        dp[j++] = *fp++;
 536
 537      if ( i + 1 < list->used )
 538        dp[j++] = (char)c;
 539    }
 540    if ( dp != empty )
 541      dp[j] = 0;
 542
 543    *alen = j;
 544    return dp;
 545  }
 546
 547
 548  /* The code below ensures that we have at least 4 + 1 `field' */
 549  /* elements in `list' (which are possibly NULL) so that we    */
 550  /* don't have to check the number of fields in most cases.    */
 551
 552  static FT_Error
 553  _bdf_list_split( _bdf_list_t*   list,
 554                   char*          separators,
 555                   char*          line,
 556                   unsigned long  linelen )
 557  {
 558    int       mult, final_empty;
 559    char      *sp, *ep, *end;
 560    char      seps[32];
 561    FT_Error  error = BDF_Err_Ok;
 562
 563
 564    /* Initialize the list. */
 565    list->used = 0;
 566    if ( list->size )
 567    {
 568      list->field[0] = (char*)empty;
 569      list->field[1] = (char*)empty;
 570      list->field[2] = (char*)empty;
 571      list->field[3] = (char*)empty;
 572    }
 573
 574    /* If the line is empty, then simply return. */
 575    if ( linelen == 0 || line[0] == 0 )
 576      goto Exit;
 577
 578    /* In the original code, if the `separators' parameter is NULL or */
 579    /* empty, the list is split into individual bytes.  We don't need */
 580    /* this, so an error is signaled.                                 */
 581    if ( separators == 0 || *separators == 0 )
 582    {
 583      error = BDF_Err_Invalid_Argument;
 584      goto Exit;
 585    }
 586
 587    /* Prepare the separator bitmap. */
 588    FT_MEM_ZERO( seps, 32 );
 589
 590    /* If the very last character of the separator string is a plus, then */
 591    /* set the `mult' flag to indicate that multiple separators should be */
 592    /* collapsed into one.                                                */
 593    for ( mult = 0, sp = separators; sp && *sp; sp++ )
 594    {
 595      if ( *sp == '+' && *( sp + 1 ) == 0 )
 596        mult = 1;
 597      else
 598        setsbit( seps, *sp );
 599    }
 600
 601    /* Break the line up into fields. */
 602    for ( final_empty = 0, sp = ep = line, end = sp + linelen;
 603          sp < end && *sp; )
 604    {
 605      /* Collect everything that is not a separator. */
 606      for ( ; *ep && !sbitset( seps, *ep ); ep++ )
 607        ;
 608
 609      /* Resize the list if necessary. */
 610      if ( list->used == list->size )
 611      {
 612        error = _bdf_list_ensure( list, list->used + 1 );
 613        if ( error )
 614          goto Exit;
 615      }
 616
 617      /* Assign the field appropriately. */
 618      list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
 619
 620      sp = ep;
 621
 622      if ( mult )
 623      {
 624        /* If multiple separators should be collapsed, do it now by */
 625        /* setting all the separator characters to 0.               */
 626        for ( ; *ep && sbitset( seps, *ep ); ep++ )
 627          *ep = 0;
 628      }
 629      else if ( *ep != 0 )
 630        /* Don't collapse multiple separators by making them 0, so just */
 631        /* make the one encountered 0.                                  */
 632        *ep++ = 0;
 633
 634      final_empty = ( ep > sp && *ep == 0 );
 635      sp = ep;
 636    }
 637
 638    /* Finally, NULL-terminate the list. */
 639    if ( list->used + final_empty >= list->size )
 640    {
 641      error = _bdf_list_ensure( list, list->used + final_empty + 1 );
 642      if ( error )
 643        goto Exit;
 644    }
 645
 646    if ( final_empty )
 647      list->field[list->used++] = (char*)empty;
 648
 649    list->field[list->used] = 0;
 650
 651  Exit:
 652    return error;
 653  }
 654
 655
 656#define NO_SKIP  256  /* this value cannot be stored in a 'char' */
 657
 658
 659  static FT_Error
 660  _bdf_readstream( FT_Stream         stream,
 661                   _bdf_line_func_t  callback,
 662                   void*             client_data,
 663                   unsigned long    *lno )
 664  {
 665    _bdf_line_func_t  cb;
 666    unsigned long     lineno, buf_size;
 667    int               refill, hold, to_skip;
 668    ptrdiff_t         bytes, start, end, cursor, avail;
 669    char*             buf = 0;
 670    FT_Memory         memory = stream->memory;
 671    FT_Error          error = BDF_Err_Ok;
 672
 673
 674    if ( callback == 0 )
 675    {
 676      error = BDF_Err_Invalid_Argument;
 677      goto Exit;
 678    }
 679
 680    /* initial size and allocation of the input buffer */
 681    buf_size = 1024;
 682
 683    if ( FT_NEW_ARRAY( buf, buf_size ) )
 684      goto Exit;
 685
 686    cb      = callback;
 687    lineno  = 1;
 688    buf[0]  = 0;
 689    start   = 0;
 690    end     = 0;
 691    avail   = 0;
 692    cursor  = 0;
 693    refill  = 1;
 694    to_skip = NO_SKIP;
 695    bytes   = 0;        /* make compiler happy */
 696
 697    for (;;)
 698    {
 699      if ( refill )
 700      {
 701        bytes  = (ptrdiff_t)FT_Stream_TryRead(
 702                   stream, (FT_Byte*)buf + cursor,
 703                   (FT_ULong)( buf_size - cursor ) );
 704        avail  = cursor + bytes;
 705        cursor = 0;
 706        refill = 0;
 707      }
 708
 709      end = start;
 710
 711      /* should we skip an optional character like \n or \r? */
 712      if ( start < avail && buf[start] == to_skip )
 713      {
 714        start  += 1;
 715        to_skip = NO_SKIP;
 716        continue;
 717      }
 718
 719      /* try to find the end of the line */
 720      while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
 721        end++;
 722
 723      /* if we hit the end of the buffer, try shifting its content */
 724      /* or even resizing it                                       */
 725      if ( end >= avail )
 726      {
 727        if ( bytes == 0 )  /* last line in file doesn't end in \r or \n */
 728          break;           /* ignore it then exit                       */
 729
 730        if ( start == 0 )
 731        {
 732          /* this line is definitely too long; try resizing the input */
 733          /* buffer a bit to handle it.                               */
 734          FT_ULong  new_size;
 735
 736
 737          if ( buf_size >= 65536UL )  /* limit ourselves to 64KByte */
 738          {
 739            FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno ));
 740            error = BDF_Err_Invalid_Argument;
 741            goto Exit;
 742          }
 743
 744          new_size = buf_size * 2;
 745          if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
 746            goto Exit;
 747
 748          cursor   = buf_size;
 749          buf_size = new_size;
 750        }
 751        else
 752        {
 753          bytes = avail - start;
 754
 755          FT_MEM_COPY( buf, buf + start, bytes );
 756
 757          cursor = bytes;
 758          avail -= bytes;
 759          start  = 0;
 760        }
 761        refill = 1;
 762        continue;
 763      }
 764
 765      /* Temporarily NUL-terminate the line. */
 766      hold     = buf[end];
 767      buf[end] = 0;
 768
 769      /* XXX: Use encoding independent value for 0x1a */
 770      if ( buf[start] != '#' && buf[start] != 0x1a && end > start )
 771      {
 772        error = (*cb)( buf + start, end - start, lineno,
 773                       (void*)&cb, client_data );
 774        /* Redo if we have encountered CHARS without properties. */
 775        if ( error == -1 )
 776          error = (*cb)( buf + start, end - start, lineno,
 777                         (void*)&cb, client_data );
 778        if ( error )
 779          break;
 780      }
 781
 782      lineno  += 1;
 783      buf[end] = (char)hold;
 784      start    = end + 1;
 785
 786      if ( hold == '\n' )
 787        to_skip = '\r';
 788      else if ( hold == '\r' )
 789        to_skip = '\n';
 790      else
 791        to_skip = NO_SKIP;
 792    }
 793
 794    *lno = lineno;
 795
 796  Exit:
 797    FT_FREE( buf );
 798    return error;
 799  }
 800
 801
 802  /* XXX: make this work with EBCDIC also */
 803
 804  static const unsigned char  a2i[128] =
 805  {
 806    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 807    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 808    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 809    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 810    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
 811    0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
 812    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 813    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 814    0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
 815    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 816    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 817  };
 818
 819  static const unsigned char  odigits[32] =
 820  {
 821    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
 822    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 823    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 824    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 825  };
 826
 827  static const unsigned char  ddigits[32] =
 828  {
 829    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
 830    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 831    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 832    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 833  };
 834
 835  static const unsigned char  hdigits[32] =
 836  {
 837    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
 838    0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
 839    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 840    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 841  };
 842
 843
 844#define isdigok( m, d )  (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
 845
 846
 847  /* Routine to convert an ASCII string into an unsigned long integer. */
 848  static unsigned long
 849  _bdf_atoul( char*   s,
 850              char**  end,
 851              int     base )
 852  {
 853    unsigned long         v;
 854    const unsigned char*  dmap;
 855
 856
 857    if ( s == 0 || *s == 0 )
 858      return 0;
 859
 860    /* Make sure the radix is something recognizable.  Default to 10. */
 861    switch ( base )
 862    {
 863    case 8:
 864      dmap = odigits;
 865      break;
 866    case 16:
 867      dmap = hdigits;
 868      break;
 869    default:
 870      base = 10;
 871      dmap = ddigits;
 872      break;
 873    }
 874
 875    /* Check for the special hex prefix. */
 876    if ( *s == '0'                                  &&
 877         ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
 878    {
 879      base = 16;
 880      dmap = hdigits;
 881      s   += 2;
 882    }
 883
 884    for ( v = 0; isdigok( dmap, *s ); s++ )
 885      v = v * base + a2i[(int)*s];
 886
 887    if ( end != 0 )
 888      *end = s;
 889
 890    return v;
 891  }
 892
 893
 894  /* Routine to convert an ASCII string into an signed long integer. */
 895  static long
 896  _bdf_atol( char*   s,
 897             char**  end,
 898             int     base )
 899  {
 900    long                  v, neg;
 901    const unsigned char*  dmap;
 902
 903
 904    if ( s == 0 || *s == 0 )
 905      return 0;
 906
 907    /* Make sure the radix is something recognizable.  Default to 10. */
 908    switch ( base )
 909    {
 910    case 8:
 911      dmap = odigits;
 912      break;
 913    case 16:
 914      dmap = hdigits;
 915      break;
 916    default:
 917      base = 10;
 918      dmap = ddigits;
 919      break;
 920    }
 921
 922    /* Check for a minus sign. */
 923    neg = 0;
 924    if ( *s == '-' )
 925    {
 926      s++;
 927      neg = 1;
 928    }
 929
 930    /* Check for the special hex prefix. */
 931    if ( *s == '0'                                  &&
 932         ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
 933    {
 934      base = 16;
 935      dmap = hdigits;
 936      s   += 2;
 937    }
 938
 939    for ( v = 0; isdigok( dmap, *s ); s++ )
 940      v = v * base + a2i[(int)*s];
 941
 942    if ( end != 0 )
 943      *end = s;
 944
 945    return ( !neg ) ? v : -v;
 946  }
 947
 948
 949  /* Routine to convert an ASCII string into an signed short integer. */
 950  static short
 951  _bdf_atos( char*   s,
 952             char**  end,
 953             int     base )
 954  {
 955    short                 v, neg;
 956    const unsigned char*  dmap;
 957
 958
 959    if ( s == 0 || *s == 0 )
 960      return 0;
 961
 962    /* Make sure the radix is something recognizable.  Default to 10. */
 963    switch ( base )
 964    {
 965    case 8:
 966      dmap = odigits;
 967      break;
 968    case 16:
 969      dmap = hdigits;
 970      break;
 971    default:
 972      base = 10;
 973      dmap = ddigits;
 974      break;
 975    }
 976
 977    /* Check for a minus. */
 978    neg = 0;
 979    if ( *s == '-' )
 980    {
 981      s++;
 982      neg = 1;
 983    }
 984
 985    /* Check for the special hex prefix. */
 986    if ( *s == '0'                                  &&
 987         ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
 988    {
 989      base = 16;
 990      dmap = hdigits;
 991      s   += 2;
 992    }
 993
 994    for ( v = 0; isdigok( dmap, *s ); s++ )
 995      v = (short)( v * base + a2i[(int)*s] );
 996
 997    if ( end != 0 )
 998      *end = s;
 999
1000    return (short)( ( !neg ) ? v : -v );
1001  }
1002
1003
1004  /* Routine to compare two glyphs by encoding so they can be sorted. */
1005  static int
1006  by_encoding( const void*  a,
1007               const void*  b )
1008  {
1009    bdf_glyph_t  *c1, *c2;
1010
1011
1012    c1 = (bdf_glyph_t *)a;
1013    c2 = (bdf_glyph_t *)b;
1014
1015    if ( c1->encoding < c2->encoding )
1016      return -1;
1017
1018    if ( c1->encoding > c2->encoding )
1019      return 1;
1020
1021    return 0;
1022  }
1023
1024
1025  static FT_Error
1026  bdf_create_property( char*        name,
1027                       int          format,
1028                       bdf_font_t*  font )
1029  {
1030    size_t           n;
1031    bdf_property_t*  p;
1032    FT_Memory        memory = font->memory;
1033    FT_Error         error = BDF_Err_Ok;
1034
1035
1036    /* First check whether the property has        */
1037    /* already been added or not.  If it has, then */
1038    /* simply ignore it.                           */
1039    if ( hash_lookup( name, &(font->proptbl) ) )
1040      goto Exit;
1041
1042    if ( FT_RENEW_ARRAY( font->user_props,
1043                         font->nuser_props,
1044                         font->nuser_props + 1 ) )
1045      goto Exit;
1046
1047    p = font->user_props + font->nuser_props;
1048    FT_ZERO( p );
1049
1050    n = ft_strlen( name ) + 1;
1051    if ( n > FT_ULONG_MAX )
1052      return BDF_Err_Invalid_Argument;
1053
1054    if ( FT_NEW_ARRAY( p->name, n ) )
1055      goto Exit;
1056
1057    FT_MEM_COPY( (char *)p->name, name, n );
1058
1059    p->format  = format;
1060    p->builtin = 0;
1061
1062    n = _num_bdf_properties + font->nuser_props;
1063
1064    error = hash_insert( p->name, n, &(font->proptbl), memory );
1065    if ( error )
1066      goto Exit;
1067
1068    font->nuser_props++;
1069
1070  Exit:
1071    return error;
1072  }
1073
1074
1075  FT_LOCAL_DEF( bdf_property_t * )
1076  bdf_get_property( char*        name,
1077                    bdf_font_t*  font )
1078  {
1079    hashnode  hn;
1080    size_t    propid;
1081
1082
1083    if ( name == 0 || *name == 0 )
1084      return 0;
1085
1086    if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1087      return 0;
1088
1089    propid = hn->data;
1090    if ( propid >= _num_bdf_properties )
1091      return font->user_props + ( propid - _num_bdf_properties );
1092
1093    return (bdf_property_t*)_bdf_properties + propid;
1094  }
1095
1096
1097  /*************************************************************************/
1098  /*                                                                       */
1099  /* BDF font file parsing flags and functions.                            */
1100  /*                                                                       */
1101  /*************************************************************************/
1102
1103
1104  /* Parse flags. */
1105
1106#define _BDF_START      0x0001
1107#define _BDF_FONT_NAME  0x0002
1108#define _BDF_SIZE       0x0004
1109#define _BDF_FONT_BBX   0x0008
1110#define _BDF_PROPS      0x0010
1111#define _BDF_GLYPHS     0x0020
1112#define _BDF_GLYPH      0x0040
1113#define _BDF_ENCODING   0x0080
1114#define _BDF_SWIDTH     0x0100
1115#define _BDF_DWIDTH     0x0200
1116#define _BDF_BBX        0x0400
1117#define _BDF_BITMAP     0x0800
1118
1119#define _BDF_SWIDTH_ADJ  0x1000
1120
1121#define _BDF_GLYPH_BITS ( _BDF_GLYPH    | \
1122                          _BDF_ENCODING | \
1123                          _BDF_SWIDTH   | \
1124                          _BDF_DWIDTH   | \
1125                          _BDF_BBX      | \
1126                          _BDF_BITMAP   )
1127
1128#define _BDF_GLYPH_WIDTH_CHECK   0x40000000UL
1129#define _BDF_GLYPH_HEIGHT_CHECK  0x80000000UL
1130
1131
1132  static FT_Error
1133  _bdf_add_comment( bdf_font_t*    font,
1134                    char*          comment,
1135                    unsigned long  len )
1136  {
1137    char*      cp;
1138    FT_Memory  memory = font->memory;
1139    FT_Error   error = BDF_Err_Ok;
1140
1141
1142    if ( FT_RENEW_ARRAY( font->comments,
1143                         font->comments_len,
1144                         font->comments_len + len + 1 ) )
1145      goto Exit;
1146
1147    cp = font->comments + font->comments_len;
1148
1149    FT_MEM_COPY( cp, comment, len );
1150    cp[len] = '\n';
1151
1152    font->comments_len += len + 1;
1153
1154  Exit:
1155    return error;
1156  }
1157
1158
1159  /* Set the spacing from the font name if it exists, or set it to the */
1160  /* default specified in the options.                                 */
1161  static FT_Error
1162  _bdf_set_default_spacing( bdf_font_t*     font,
1163                            bdf_options_t*  opts,
1164                            unsigned long   lineno )
1165  {
1166    size_t       len;
1167    char         name[256];
1168    _bdf_list_t  list;
1169    FT_Memory    memory;
1170    FT_Error     error = BDF_Err_Ok;
1171
1172
1173    if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1174    {
1175      error = BDF_Err_Invalid_Argument;
1176      goto Exit;
1177    }
1178
1179    memory = font->memory;
1180
1181    _bdf_list_init( &list, memory );
1182
1183    font->spacing = opts->font_spacing;
1184
1185    len = ft_strlen( font->name ) + 1;
1186    /* Limit ourselves to 256 characters in the font name. */
1187    if ( len >= 256 )
1188    {
1189      FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno ));
1190      error = BDF_Err_Invalid_Argument;
1191      goto Exit;
1192    }
1193
1194    FT_MEM_COPY( name, font->name, len );
1195
1196    error = _bdf_list_split( &list, (char *)"-", name, len );
1197    if ( error )
1198      goto Fail;
1199
1200    if ( list.used == 15 )
1201    {
1202      switch ( list.field[11][0] )
1203      {
1204      case 'C':
1205      case 'c':
1206        font->spacing = BDF_CHARCELL;
1207        break;
1208      case 'M':
1209      case 'm':
1210        font->spacing = BDF_MONOWIDTH;
1211        break;
1212      case 'P':
1213      case 'p':
1214        font->spacing = BDF_PROPORTIONAL;
1215        break;
1216      }
1217    }
1218
1219  Fail:
1220    _bdf_list_done( &list );
1221
1222  Exit:
1223    return error;
1224  }
1225
1226
1227  /* Determine whether the property is an atom or not.  If it is, then */
1228  /* clean it up so the double quotes are removed if they exist.       */
1229  static int
1230  _bdf_is_atom( char*          line,
1231                unsigned long  linelen,
1232                char**         name,
1233                char**         value,
1234                bdf_font_t*    font )
1235  {
1236    int              hold;
1237    char             *sp, *ep;
1238    bdf_property_t*  p;
1239
1240
1241    *name = sp = ep = line;
1242
1243    while ( *ep && *ep != ' ' && *ep != '\t' )
1244      ep++;
1245
1246    hold = -1;
1247    if ( *ep )
1248    {
1249      hold = *ep;
1250      *ep  = 0;
1251    }
1252
1253    p = bdf_get_property( sp, font );
1254
1255    /* Restore the character that was saved before any return can happen. */
1256    if ( hold != -1 )
1257      *ep = (char)hold;
1258
1259    /* If the property exists and is not an atom, just return here. */
1260    if ( p && p->format != BDF_ATOM )
1261      return 0;
1262
1263    /* The property is an atom.  Trim all leading and trailing whitespace */
1264    /* and double quotes for the atom value.                              */
1265    sp = ep;
1266    ep = line + linelen;
1267
1268    /* Trim the leading whitespace if it exists. */
1269    if ( *sp )
1270      *sp++ = 0;
1271    while ( *sp                           &&
1272            ( *sp == ' ' || *sp == '\t' ) )
1273      sp++;
1274
1275    /* Trim the leading double quote if it exists. */
1276    if ( *sp == '"' )
1277      sp++;
1278    *value = sp;
1279
1280    /* Trim the trailing whitespace if it exists. */
1281    while ( ep > sp                                       &&
1282            ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
1283      *--ep = 0;
1284
1285    /* Trim the trailing double quote if it exists. */
1286    if ( ep > sp && *( ep - 1 ) == '"' )
1287      *--ep = 0;
1288
1289    return 1;
1290  }
1291
1292
1293  static FT_Error
1294  _bdf_add_property( bdf_font_t*    font,
1295                     char*          name,
1296                     char*          value,
1297                     unsigned long  lineno )
1298  {
1299    size_t          propid;
1300    hashnode        hn;
1301    bdf_property_t  *prop, *fp;
1302    FT_Memory       memory = font->memory;
1303    FT_Error        error = BDF_Err_Ok;
1304
1305
1306    /* First, check whether the property already exists in the font. */
1307    if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
1308    {
1309      /* The property already exists in the font, so simply replace */
1310      /* the value of the property with the current value.          */
1311      fp = font->props + hn->data;
1312
1313      switch ( fp->format )
1314      {
1315      case BDF_ATOM:
1316        /* Delete the current atom if it exists. */
1317        FT_FREE( fp->value.atom );
1318
1319        if ( value && value[0] != 0 )
1320        {
1321          if ( FT_STRDUP( fp->value.atom, value ) )
1322            goto Exit;
1323        }
1324        break;
1325
1326      case BDF_INTEGER:
1327        fp->value.l = _bdf_atol( value, 0, 10 );
1328        break;
1329
1330      case BDF_CARDINAL:
1331        fp->value.ul = _bdf_atoul( value, 0, 10 );
1332        break;
1333
1334      default:
1335        ;
1336      }
1337
1338      goto Exit;
1339    }
1340
1341    /* See whether this property type exists yet or not. */
1342    /* If not, create it.                                */
1343    hn = hash_lookup( name, &(font->proptbl) );
1344    if ( hn == 0 )
1345    {
1346      error = bdf_create_property( name, BDF_ATOM, font );
1347      if ( error )
1348        goto Exit;
1349      hn = hash_lookup( name, &(font->proptbl) );
1350    }
1351
1352    /* Allocate another property if this is overflow. */
1353    if ( font->props_used == font->props_size )
1354    {
1355      if ( font->props_size == 0 )
1356      {
1357        if ( FT_NEW_ARRAY( font->props, 1 ) )
1358          goto Exit;
1359      }
1360      else
1361      {
1362        if ( FT_RENEW_ARRAY( font->props,
1363                             font->props_size,
1364                             font->props_size + 1 ) )
1365          goto Exit;
1366      }
1367
1368      fp = font->props + font->props_size;
1369      FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
1370      font->props_size++;
1371    }
1372
1373    propid = hn->data;
1374    if ( propid >= _num_bdf_properties )
1375      prop = font->user_props + ( propid - _num_bdf_properties );
1376    else
1377      prop = (bdf_property_t*)_bdf_properties + propid;
1378
1379    fp = font->props + font->props_used;
1380
1381    fp->name    = prop->name;
1382    fp->format  = prop->format;
1383    fp->builtin = prop->builtin;
1384
1385    switch ( prop->format )
1386    {
1387    case BDF_ATOM:
1388      fp->value.atom = 0;
1389      if ( value != 0 && value[0] )
1390      {
1391        if ( FT_STRDUP( fp->value.atom, value ) )
1392          goto Exit;
1393      }
1394      break;
1395
1396    case BDF_INTEGER:
1397      fp->value.l = _bdf_atol( value, 0, 10 );
1398      break;
1399
1400    case BDF_CARDINAL:
1401      fp->value.ul = _bdf_atoul( value, 0, 10 );
1402      break;
1403    }
1404
1405    /* If the property happens to be a comment, then it doesn't need */
1406    /* to be added to the internal hash table.                       */
1407    if ( ft_memcmp( name, "COMMENT", 7 ) != 0 )
1408    {
1409      /* Add the property to the font property table. */
1410      error = hash_insert( fp->name,
1411                           font->props_used,
1412                           (hashtable *)font->internal,
1413                           memory );
1414      if ( error )
1415        goto Exit;
1416    }
1417
1418    font->props_used++;
1419
1420    /* Some special cases need to be handled here.  The DEFAULT_CHAR       */
1421    /* property needs to be located if it exists in the property list, the */
1422    /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are        */
1423    /* present, and the SPACING property should override the default       */
1424    /* spacing.                                                            */
1425    if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
1426      font->default_char = fp->value.l;
1427    else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
1428      font->font_ascent = fp->value.l;
1429    else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
1430      font->font_descent = fp->value.l;
1431    else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
1432    {
1433      if ( !fp->value.atom )
1434      {
1435        FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
1436        error = BDF_Err_Invalid_File_Format;
1437        goto Exit;
1438      }
1439
1440      if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
1441        font->spacing = BDF_PROPORTIONAL;
1442      else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
1443        font->spacing = BDF_MONOWIDTH;
1444      else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
1445        font->spacing = BDF_CHARCELL;
1446    }
1447
1448  Exit:
1449    return error;
1450  }
1451
1452
1453  static const unsigned char nibble_mask[8] =
1454  {
1455    0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1456  };
1457
1458
1459  /* Actually parse the glyph info and bitmaps. */
1460  static FT_Error
1461  _bdf_parse_glyphs( char*          line,
1462                     unsigned long  linelen,
1463                     unsigned long  lineno,
1464                     void*          call_data,
1465                     void*          client_data )
1466  {
1467    int                c, mask_index;
1468    char*              s;
1469    unsigned char*     bp;
1470    unsigned long      i, slen, nibbles;
1471
1472    _bdf_parse_t*      p;
1473    bdf_glyph_t*       glyph;
1474    bdf_font_t*        font;
1475
1476    FT_Memory          memory;
1477    FT_Error           error = BDF_Err_Ok;
1478
1479    FT_UNUSED( call_data );
1480    FT_UNUSED( lineno );        /* only used in debug mode */
1481
1482
1483    p = (_bdf_parse_t *)client_data;
1484
1485    font   = p->font;
1486    memory = font->memory;
1487
1488    /* Check for a comment. */
1489    if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1490    {
1491      linelen -= 7;
1492
1493      s = line + 7;
1494      if ( *s != 0 )
1495      {
1496        s++;
1497        linelen--;
1498      }
1499      error = _bdf_add_comment( p->font, s, linelen );
1500      goto Exit;
1501    }
1502
1503    /* The very first thing expected is the number of glyphs. */
1504    if ( !( p->flags & _BDF_GLYPHS ) )
1505    {
1506      if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1507      {
1508        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1509        error = BDF_Err_Missing_Chars_Field;
1510        goto Exit;
1511      }
1512
1513      error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1514      if ( error )
1515        goto Exit;
1516      p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1517
1518      /* Make sure the number of glyphs is non-zero. */
1519      if ( p->cnt == 0 )
1520        font->glyphs_size = 64;
1521
1522      /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1523      /* number of code points available in Unicode).                 */
1524      if ( p->cnt >= 0x110000UL )
1525      {
1526        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
1527        error = BDF_Err_Invalid_Argument;
1528        goto Exit;
1529      }
1530
1531      if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1532        goto Exit;
1533
1534      p->flags |= _BDF_GLYPHS;
1535
1536      goto Exit;
1537    }
1538
1539    /* Check for the ENDFONT field. */
1540    if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1541    {
1542      /* Sort the glyphs by encoding. */
1543      ft_qsort( (char *)font->glyphs,
1544                font->glyphs_used,
1545                sizeof ( bdf_glyph_t ),
1546                by_encoding );
1547
1548      p->flags &= ~_BDF_START;
1549
1550      goto Exit;
1551    }
1552
1553    /* Check for the ENDCHAR field. */
1554    if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1555    {
1556      p->glyph_enc = 0;
1557      p->flags    &= ~_BDF_GLYPH_BITS;
1558
1559      goto Exit;
1560    }
1561
1562    /* Check whether a glyph is being scanned but should be */
1563    /* ignored because it is an unencoded glyph.            */
1564    if ( ( p->flags & _BDF_GLYPH )     &&
1565         p->glyph_enc            == -1 &&
1566         p->opts->keep_unencoded == 0  )
1567      goto Exit;
1568
1569    /* Check for the STARTCHAR field. */
1570    if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1571    {
1572      /* Set the character name in the parse info first until the */
1573      /* encoding can be checked for an unencoded character.      */
1574      FT_FREE( p->glyph_name );
1575
1576      error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1577      if ( error )
1578        goto Exit;
1579
1580      _bdf_list_shift( &p->list, 1 );
1581
1582      s = _bdf_list_join( &p->list, ' ', &slen );
1583
1584      if ( !s )
1585      {
1586        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
1587        error = BDF_Err_Invalid_File_Format;
1588        goto Exit;
1589      }
1590
1591      if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1592        goto Exit;
1593
1594      FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1595
1596      p->flags |= _BDF_GLYPH;
1597
1598      FT_TRACE4(( DBGMSG1, lineno, s ));
1599
1600      goto Exit;
1601    }
1602
1603    /* Check for the ENCODING field. */
1604    if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1605    {
1606      if ( !( p->flags & _BDF_GLYPH ) )
1607      {
1608        /* Missing STARTCHAR field. */
1609        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1610        error = BDF_Err_Missing_Startchar_Field;
1611        goto Exit;
1612      }
1613
1614      error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1615      if ( error )
1616        goto Exit;
1617
1618      p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
1619
1620      /* Normalize negative encoding values.  The specification only */
1621      /* allows -1, but we can be more generous here.                */
1622      if ( p->glyph_enc < -1 )
1623        p->glyph_enc = -1;
1624
1625      /* Check for alternative encoding format. */
1626      if ( p->glyph_enc == -1 && p->list.used > 2 )
1627        p->glyph_enc = _bdf_atol( p->list.field[2], 0, 10 );
1628
1629      FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1630
1631      /* Check that the encoding is in the Unicode range because  */
1632      /* otherwise p->have (a bitmap with static size) overflows. */
1633      if ( p->glyph_enc > 0                               &&
1634           (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 )
1635      {
1636        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "ENCODING" ));
1637        error = BDF_Err_Invalid_File_Format;
1638        goto Exit;
1639      }
1640
1641      /* Check whether this encoding has already been encountered. */
1642      /* If it has then change it to unencoded so it gets added if */
1643      /* indicated.                                                */
1644      if ( p->glyph_enc >= 0 )
1645      {
1646        if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1647        {
1648          /* Emit a message saying a glyph has been moved to the */
1649          /* unencoded area.                                     */
1650          FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1651                      p->glyph_enc, p->glyph_name ));
1652          p->glyph_enc = -1;
1653          font->modified = 1;
1654        }
1655        else
1656          _bdf_set_glyph_modified( p->have, p->glyph_enc );
1657      }
1658
1659      if ( p->glyph_enc >= 0 )
1660      {
1661        /* Make sure there are enough glyphs allocated in case the */
1662        /* number of characters happen to be wrong.                */
1663        if ( font->glyphs_used == font->glyphs_size )
1664        {
1665          if ( FT_RENEW_ARRAY( font->glyphs,
1666                               font->glyphs_size,
1667                               font->glyphs_size + 64 ) )
1668            goto Exit;
1669
1670          font->glyphs_size += 64;
1671        }
1672
1673        glyph           = font->glyphs + font->glyphs_used++;
1674        glyph->name     = p->glyph_name;
1675        glyph->encoding = p->glyph_enc;
1676
1677        /* Reset the initial glyph info. */
1678        p->glyph_name = 0;
1679      }
1680      else
1681      {
1682        /* Unencoded glyph.  Check whether it should */
1683        /* be added or not.                          */
1684        if ( p->opts->keep_unencoded != 0 )
1685        {
1686          /* Allocate the next unencoded glyph. */
1687          if ( font->unencoded_used == font->unencoded_size )
1688          {
1689            if ( FT_RENEW_ARRAY( font->unencoded ,
1690                                 font->unencoded_size,
1691                                 font->unencoded_size + 4 ) )
1692              goto Exit;
1693
1694            font->unencoded_size += 4;
1695          }
1696
1697          glyph           = font->unencoded + font->unencoded_used;
1698          glyph->name     = p->glyph_name;
1699          glyph->encoding = font->unencoded_used++;
1700        }
1701        else
1702          /* Free up the glyph name if the unencoded shouldn't be */
1703          /* kept.                                                */
1704          FT_FREE( p->glyph_name );
1705
1706        p->glyph_name = 0;
1707      }
1708
1709      /* Clear the flags that might be added when width and height are */
1710      /* checked for consistency.                                      */
1711      p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1712
1713      p->flags |= _BDF_ENCODING;
1714
1715      goto Exit;
1716    }
1717
1718    /* Point at the glyph being constructed. */
1719    if ( p->glyph_enc == -1 )
1720      glyph = font->unencoded + ( font->unencoded_used - 1 );
1721    else
1722      glyph = font->glyphs + ( font->glyphs_used - 1 );
1723
1724    /* Check whether a bitmap is being constructed. */
1725    if ( p->flags & _BDF_BITMAP )
1726    {
1727      /* If there are more rows than are specified in the glyph metrics, */
1728      /* ignore the remaining lines.                                     */
1729      if ( p->row >= (unsigned long)glyph->bbx.height )
1730      {
1731        if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1732        {
1733          FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, 

Large files files are truncated, but you can click here to view the full file