source: trunk/poppler/freetype2/src/bdf/bdflib.c @ 209

Last change on this file since 209 was 209, checked in by Eugene Romanenko, 14 years ago

PDF plugin: freetype library updated to version 2.3.5

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