source: trunk/poppler/freetype-2.1.10/src/bdf/bdflib.c @ 2

Last change on this file since 2 was 2, checked in by Eugene Romanenko, 15 years ago

First import

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