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

Last change on this file since 269 was 269, checked in by Eugene Romanenko, 13 years ago

PDF plugin: freetype library updated to version 2.3.9

File size: 71.6 KB
Line 
1/*
2 * Copyright 2000 Computing Research Labs, New Mexico State University
3 * Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009
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 )
1398      {
1399        error = BDF_Err_Invalid_File_Format;
1400        goto Exit;
1401      }
1402
1403      if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
1404        font->spacing = BDF_PROPORTIONAL;
1405      else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
1406        font->spacing = BDF_MONOWIDTH;
1407      else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
1408        font->spacing = BDF_CHARCELL;
1409    }
1410
1411  Exit:
1412    return error;
1413  }
1414
1415
1416  static const unsigned char nibble_mask[8] =
1417  {
1418    0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1419  };
1420
1421
1422  /* Actually parse the glyph info and bitmaps. */
1423  static FT_Error
1424  _bdf_parse_glyphs( char*          line,
1425                     unsigned long  linelen,
1426                     unsigned long  lineno,
1427                     void*          call_data,
1428                     void*          client_data )
1429  {
1430    int                c, mask_index;
1431    char*              s;
1432    unsigned char*     bp;
1433    unsigned long      i, slen, nibbles;
1434
1435    _bdf_parse_t*      p;
1436    bdf_glyph_t*       glyph;
1437    bdf_font_t*        font;
1438
1439    FT_Memory          memory;
1440    FT_Error           error = BDF_Err_Ok;
1441
1442    FT_UNUSED( call_data );
1443    FT_UNUSED( lineno );        /* only used in debug mode */
1444
1445
1446    p = (_bdf_parse_t *)client_data;
1447
1448    font   = p->font;
1449    memory = font->memory;
1450
1451    /* Check for a comment. */
1452    if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1453    {
1454      linelen -= 7;
1455
1456      s = line + 7;
1457      if ( *s != 0 )
1458      {
1459        s++;
1460        linelen--;
1461      }
1462      error = _bdf_add_comment( p->font, s, linelen );
1463      goto Exit;
1464    }
1465
1466    /* The very first thing expected is the number of glyphs. */
1467    if ( !( p->flags & _BDF_GLYPHS ) )
1468    {
1469      if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1470      {
1471        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1472        error = BDF_Err_Missing_Chars_Field;
1473        goto Exit;
1474      }
1475
1476      error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1477      if ( error )
1478        goto Exit;
1479      p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1480
1481      /* Make sure the number of glyphs is non-zero. */
1482      if ( p->cnt == 0 )
1483        font->glyphs_size = 64;
1484
1485      /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1486      /* number of code points available in Unicode).                 */
1487      if ( p->cnt >= 1114112UL )
1488      {
1489        error = BDF_Err_Invalid_Argument;
1490        goto Exit;
1491      }
1492
1493      if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1494        goto Exit;
1495
1496      p->flags |= _BDF_GLYPHS;
1497
1498      goto Exit;
1499    }
1500
1501    /* Check for the ENDFONT field. */
1502    if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1503    {
1504      /* Sort the glyphs by encoding. */
1505      ft_qsort( (char *)font->glyphs,
1506                font->glyphs_used,
1507                sizeof ( bdf_glyph_t ),
1508                by_encoding );
1509
1510      p->flags &= ~_BDF_START;
1511
1512      goto Exit;
1513    }
1514
1515    /* Check for the ENDCHAR field. */
1516    if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1517    {
1518      p->glyph_enc = 0;
1519      p->flags    &= ~_BDF_GLYPH_BITS;
1520
1521      goto Exit;
1522    }
1523
1524    /* Check to see whether a glyph is being scanned but should be */
1525    /* ignored because it is an unencoded glyph.                   */
1526    if ( ( p->flags & _BDF_GLYPH )     &&
1527         p->glyph_enc            == -1 &&
1528         p->opts->keep_unencoded == 0  )
1529      goto Exit;
1530
1531    /* Check for the STARTCHAR field. */
1532    if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1533    {
1534      /* Set the character name in the parse info first until the */
1535      /* encoding can be checked for an unencoded character.      */
1536      FT_FREE( p->glyph_name );
1537
1538      error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1539      if ( error )
1540        goto Exit;
1541
1542      _bdf_list_shift( &p->list, 1 );
1543
1544      s = _bdf_list_join( &p->list, ' ', &slen );
1545
1546      if ( !s )
1547      {
1548        error = BDF_Err_Invalid_File_Format;
1549        goto Exit;
1550      }
1551
1552      if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1553        goto Exit;
1554
1555      FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1556
1557      p->flags |= _BDF_GLYPH;
1558
1559      goto Exit;
1560    }
1561
1562    /* Check for the ENCODING field. */
1563    if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1564    {
1565      if ( !( p->flags & _BDF_GLYPH ) )
1566      {
1567        /* Missing STARTCHAR field. */
1568        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1569        error = BDF_Err_Missing_Startchar_Field;
1570        goto Exit;
1571      }
1572
1573      error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1574      if ( error )
1575        goto Exit;
1576
1577      p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
1578
1579      /* Check that the encoding is in the range [0,65536] because        */
1580      /* otherwise p->have (a bitmap with static size) overflows.         */
1581      if ( (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 )
1582      {
1583        error = BDF_Err_Invalid_File_Format;
1584        goto Exit;
1585      }
1586
1587      /* Check to see whether this encoding has already been encountered. */
1588      /* If it has then change it to unencoded so it gets added if        */
1589      /* indicated.                                                       */
1590      if ( p->glyph_enc >= 0 )
1591      {
1592        if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1593        {
1594          /* Emit a message saying a glyph has been moved to the */
1595          /* unencoded area.                                     */
1596          FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1597                      p->glyph_enc, p->glyph_name ));
1598          p->glyph_enc = -1;
1599          font->modified = 1;
1600        }
1601        else
1602          _bdf_set_glyph_modified( p->have, p->glyph_enc );
1603      }
1604
1605      if ( p->glyph_enc >= 0 )
1606      {
1607        /* Make sure there are enough glyphs allocated in case the */
1608        /* number of characters happen to be wrong.                */
1609        if ( font->glyphs_used == font->glyphs_size )
1610        {
1611          if ( FT_RENEW_ARRAY( font->glyphs,
1612                               font->glyphs_size,
1613                               font->glyphs_size + 64 ) )
1614            goto Exit;
1615
1616          font->glyphs_size += 64;
1617        }
1618
1619        glyph           = font->glyphs + font->glyphs_used++;
1620        glyph->name     = p->glyph_name;
1621        glyph->encoding = p->glyph_enc;
1622
1623        /* Reset the initial glyph info. */
1624        p->glyph_name = 0;
1625      }
1626      else
1627      {
1628        /* Unencoded glyph.  Check to see whether it should */
1629        /* be added or not.                                 */
1630        if ( p->opts->keep_unencoded != 0 )
1631        {
1632          /* Allocate the next unencoded glyph. */
1633          if ( font->unencoded_used == font->unencoded_size )
1634          {
1635            if ( FT_RENEW_ARRAY( font->unencoded ,
1636                                 font->unencoded_size,
1637                                 font->unencoded_size + 4 ) )
1638              goto Exit;
1639
1640            font->unencoded_size += 4;
1641          }
1642
1643          glyph           = font->unencoded + font->unencoded_used;
1644          glyph->name     = p->glyph_name;
1645          glyph->encoding = font->unencoded_used++;
1646        }
1647        else
1648          /* Free up the glyph name if the unencoded shouldn't be */
1649          /* kept.                                                */
1650          FT_FREE( p->glyph_name );
1651
1652        p->glyph_name = 0;
1653      }
1654
1655      /* Clear the flags that might be added when width and height are */
1656      /* checked for consistency.                                      */
1657      p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1658
1659      p->flags |= _BDF_ENCODING;
1660
1661      goto Exit;
1662    }
1663
1664    /* Point at the glyph being constructed. */
1665    if ( p->glyph_enc == -1 )
1666      glyph = font->unencoded + ( font->unencoded_used - 1 );
1667    else
1668      glyph = font->glyphs + ( font->glyphs_used - 1 );
1669
1670    /* Check to see whether a bitmap is being constructed. */
1671    if ( p->flags & _BDF_BITMAP )
1672    {
1673      /* If there are more rows than are specified in the glyph metrics, */
1674      /* ignore the remaining lines.                                     */
1675      if ( p->row >= (unsigned long)glyph->bbx.height )
1676      {
1677        if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1678        {
1679          FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1680          p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
1681          font->modified = 1;
1682        }
1683
1684        goto Exit;
1685      }
1686
1687      /* Only collect the number of nibbles indicated by the glyph     */
1688      /* metrics.  If there are more columns, they are simply ignored. */
1689      nibbles = glyph->bpr << 1;
1690      bp      = glyph->bitmap + p->row * glyph->bpr;
1691
1692      for ( i = 0; i < nibbles; i++ )
1693      {
1694        c = line[i];
1695        *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
1696        if ( i + 1 < nibbles && ( i & 1 ) )
1697          *++bp = 0;
1698      }
1699
1700      /* Remove possible garbage at the right. */
1701      mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
1702      if ( glyph->bbx.width )
1703        *bp &= nibble_mask[mask_index];
1704
1705      /* If any line has extra columns, indicate they have been removed. */
1706      if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
1707           !( p->flags & _BDF_GLYPH_WIDTH_CHECK )                   )
1708      {
1709        FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1710        p->flags       |= _BDF_GLYPH_WIDTH_CHECK;
1711        font->modified  = 1;
1712      }
1713
1714      p->row++;
1715      goto Exit;
1716    }
1717
1718    /* Expect the SWIDTH (scalable width) field next. */
1719    if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1720    {
1721      if ( !( p->flags & _BDF_ENCODING ) )
1722      {
1723        /* Missing ENCODING field. */
1724        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1725        error = BDF_Err_Missing_Encoding_Field;
1726        goto Exit;
1727      }
1728
1729      error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1730      if ( error )
1731        goto Exit;
1732
1733      glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
1734      p->flags |= _BDF_SWIDTH;
1735
1736      goto Exit;
1737    }
1738
1739    /* Expect the DWIDTH (scalable width) field next. */
1740    if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1741    {
1742      error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1743      if ( error )
1744        goto Exit;
1745
1746      glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
1747
1748      if ( !( p->flags & _BDF_SWIDTH ) )
1749      {
1750        /* Missing SWIDTH field.  Emit an auto correction message and set */
1751        /* the scalable width from the device width.                      */
1752        FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1753
1754        glyph->swidth = (unsigned short)FT_MulDiv(
1755                          glyph->dwidth, 72000L,
1756                          (FT_Long)( font->point_size *
1757                                     font->resolution_x ) );
1758      }
1759
1760      p->flags |= _BDF_DWIDTH;
1761      goto Exit;
1762    }
1763
1764    /* Expect the BBX field next. */
1765    if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1766    {
1767      error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1768      if ( error )
1769        goto Exit;
1770
1771      glyph->bbx.width    = _bdf_atos( p->list.field[1], 0, 10 );
1772      glyph->bbx.height   = _bdf_atos( p->list.field[2], 0, 10 );
1773      glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1774      glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1775
1776      /* Generate the ascent and descent of the character. */
1777      glyph->bbx.ascent  = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1778      glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
1779
1780      /* Determine the overall font bounding box as the characters are */
1781      /* loaded so corrections can be done later if indicated.         */
1782      p->maxas    = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1783      p->maxds    = (short)FT_MAX( glyph->bbx.descent, p->maxds );
1784
1785      p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
1786
1787      p->maxrb    = (short)FT_MAX( p->rbearing, p->maxrb );
1788      p->minlb    = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1789      p->maxlb    = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
1790
1791      if ( !( p->flags & _BDF_DWIDTH ) )
1792      {
1793        /* Missing DWIDTH field.  Emit an auto correction message and set */
1794        /* the device width to the glyph width.                           */
1795        FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1796        glyph->dwidth = glyph->bbx.width;
1797      }
1798
1799      /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1800      /* value if necessary.                                            */
1801      if ( p->opts->correct_metrics != 0 )
1802      {
1803        /* Determine the point size of the glyph. */
1804        unsigned short  sw = (unsigned short)FT_MulDiv(
1805                               glyph->dwidth, 72000L,
1806                               (FT_Long)( font->point_size *
1807                                          font->resolution_x ) );
1808
1809
1810        if ( sw != glyph->swidth )
1811        {
1812          glyph->swidth = sw;
1813
1814          if ( p->glyph_enc == -1 )
1815            _bdf_set_glyph_modified( font->umod,
1816                                     font->unencoded_used - 1 );
1817          else
1818            _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1819
1820          p->flags       |= _BDF_SWIDTH_ADJ;
1821          font->modified  = 1;
1822        }
1823      }
1824
1825      p->flags |= _BDF_BBX;
1826      goto Exit;
1827    }
1828
1829    /* And finally, gather up the bitmap. */
1830    if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1831    {
1832      unsigned long  bitmap_size;
1833
1834
1835      if ( !( p->flags & _BDF_BBX ) )
1836      {
1837        /* Missing BBX field. */
1838        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1839        error = BDF_Err_Missing_Bbx_Field;
1840        goto Exit;
1841      }
1842
1843      /* Allocate enough space for the bitmap. */
1844      glyph->bpr   = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
1845
1846      bitmap_size = glyph->bpr * glyph->bbx.height;
1847      if ( bitmap_size > 0xFFFFU )
1848      {
1849        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
1850        error = BDF_Err_Bbx_Too_Big;
1851        goto Exit;
1852      }
1853      else
1854        glyph->bytes = (unsigned short)bitmap_size;
1855
1856      if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1857        goto Exit;
1858
1859      p->row    = 0;
1860      p->flags |= _BDF_BITMAP;
1861
1862      goto Exit;
1863    }
1864
1865    error = BDF_Err_Invalid_File_Format;
1866
1867  Exit:
1868    return error;
1869  }
1870
1871
1872  /* Load the font properties. */
1873  static FT_Error
1874  _bdf_parse_properties( char*          line,
1875                         unsigned long  linelen,
1876                         unsigned long  lineno,
1877                         void*          call_data,
1878                         void*          client_data )
1879  {
1880    unsigned long      vlen;
1881    _bdf_line_func_t*  next;
1882    _bdf_parse_t*      p;
1883    char*              name;
1884    char*              value;
1885    char               nbuf[128];
1886    FT_Error           error = BDF_Err_Ok;
1887
1888    FT_UNUSED( lineno );
1889
1890
1891    next = (_bdf_line_func_t *)call_data;
1892    p    = (_bdf_parse_t *)    client_data;
1893
1894    /* Check for the end of the properties. */
1895    if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1896    {
1897      /* If the FONT_ASCENT or FONT_DESCENT properties have not been      */
1898      /* encountered yet, then make sure they are added as properties and */
1899      /* make sure they are set from the font bounding box info.          */
1900      /*                                                                  */
1901      /* This is *always* done regardless of the options, because X11     */
1902      /* requires these two fields to compile fonts.                      */
1903      if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
1904      {
1905        p->font->font_ascent = p->font->bbx.ascent;
1906        ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
1907        error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
1908        if ( error )
1909          goto Exit;
1910
1911        FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1912        p->font->modified = 1;
1913      }
1914
1915      if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
1916      {
1917        p->font->font_descent = p->font->bbx.descent;
1918        ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
1919        error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
1920        if ( error )
1921          goto Exit;
1922
1923        FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
1924        p->font->modified = 1;
1925      }
1926
1927      p->flags &= ~_BDF_PROPS;
1928      *next     = _bdf_parse_glyphs;
1929
1930      goto Exit;
1931    }
1932
1933    /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1934    if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1935      goto Exit;
1936
1937    /* Handle COMMENT fields and properties in a special way to preserve */
1938    /* the spacing.                                                      */
1939    if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1940    {
1941      name = value = line;
1942      value += 7;
1943      if ( *value )
1944        *value++ = 0;
1945      error = _bdf_add_property( p->font, name, value );
1946      if ( error )
1947        goto Exit;
1948    }
1949    else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1950    {
1951      error = _bdf_add_property( p->font, name, value );
1952      if ( error )
1953        goto Exit;
1954    }
1955    else
1956    {
1957      error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1958      if ( error )
1959        goto Exit;
1960      name = p->list.field[0];
1961
1962      _bdf_list_shift( &p->list, 1 );
1963      value = _bdf_list_join( &p->list, ' ', &vlen );
1964
1965      error = _bdf_add_property( p->font, name, value );
1966      if ( error )
1967        goto Exit;
1968    }
1969
1970  Exit:
1971    return error;
1972  }
1973
1974
1975  /* Load the font header. */
1976  static FT_Error
1977  _bdf_parse_start( char*          line,
1978                    unsigned long  linelen,
1979                    unsigned long  lineno,
1980                    void*          call_data,
1981                    void*          client_data )
1982  {
1983    unsigned long      slen;
1984    _bdf_line_func_t*  next;
1985    _bdf_parse_t*      p;
1986    bdf_font_t*        font;
1987    char               *s;
1988
1989    FT_Memory          memory = NULL;
1990    FT_Error           error  = BDF_Err_Ok;
1991
1992    FT_UNUSED( lineno );            /* only used in debug mode */
1993
1994
1995    next = (_bdf_line_func_t *)call_data;
1996    p    = (_bdf_parse_t *)    client_data;
1997
1998    if ( p->font )
1999      memory = p->font->memory;
2000
2001    /* Check for a comment.  This is done to handle those fonts that have */
2002    /* comments before the STARTFONT line for some reason.                */
2003    if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2004    {
2005      if ( p->opts->keep_comments != 0 && p->font != 0 )
2006      {
2007        linelen -= 7;
2008
2009        s = line + 7;
2010        if ( *s != 0 )
2011        {
2012          s++;
2013          linelen--;
2014        }
2015
2016        error = _bdf_add_comment( p->font, s, linelen );
2017        if ( error )
2018          goto Exit;
2019        /* here font is not defined! */
2020      }
2021
2022      goto Exit;
2023    }
2024
2025    if ( !( p->flags & _BDF_START ) )
2026    {
2027      memory = p->memory;
2028
2029      if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2030      {
2031        /* No STARTFONT field is a good indication of a problem. */
2032        error = BDF_Err_Missing_Startfont_Field;
2033        goto Exit;
2034      }
2035
2036      p->flags = _BDF_START;
2037      font = p->font = 0;
2038
2039      if ( FT_NEW( font ) )
2040        goto Exit;
2041      p->font = font;
2042
2043      font->memory = p->memory;
2044      p->memory    = 0;
2045
2046      { /* setup */
2047        unsigned long    i;
2048        bdf_property_t*  prop;
2049
2050
2051        error = hash_init( &(font->proptbl), memory );
2052        if ( error )
2053          goto Exit;
2054        for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
2055              i < _num_bdf_properties; i++, prop++ )
2056        {
2057          error = hash_insert( prop->name, (void *)i,
2058                               &(font->proptbl), memory );
2059          if ( error )
2060            goto Exit;
2061        }
2062      }
2063
2064      if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2065        goto Exit;
2066      error = hash_init( (hashtable *)p->font->internal,memory );
2067      if ( error )
2068        goto Exit;
2069      p->font->spacing      = p->opts->font_spacing;
2070      p->font->default_char = -1;
2071
2072      goto Exit;
2073    }
2074
2075    /* Check for the start of the properties. */
2076    if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2077    {
2078      error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
2079      if ( error )
2080        goto Exit;
2081      /* at this point, `p->font' can't be NULL */
2082      p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2083
2084      if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2085        goto Exit;
2086
2087      p->flags |= _BDF_PROPS;
2088      *next     = _bdf_parse_properties;
2089
2090      goto Exit;
2091    }
2092
2093    /* Check for the FONTBOUNDINGBOX field. */
2094    if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2095    {
2096      if ( !(p->flags & _BDF_SIZE ) )
2097      {
2098        /* Missing the SIZE field. */
2099        FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2100        error = BDF_Err_Missing_Size_Field;
2101        goto Exit;
2102      }
2103
2104      error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
2105      if ( error )
2106        goto Exit;
2107
2108      p->font->bbx.width  = _bdf_atos( p->list.field[1], 0, 10 );
2109      p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2110
2111      p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2112      p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2113
2114      p->font->bbx.ascent  = (short)( p->font->bbx.height +
2115                                      p->font->bbx.y_offset );
2116
2117      p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
2118
2119      p->flags |= _BDF_FONT_BBX;
2120
2121      goto Exit;
2122    }
2123
2124    /* The next thing to check for is the FONT field. */
2125    if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2126    {
2127      error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
2128      if ( error )
2129        goto Exit;
2130      _bdf_list_shift( &p->list, 1 );
2131
2132      s = _bdf_list_join( &p->list, ' ', &slen );
2133
2134      if ( !s )
2135      {
2136        error = BDF_Err_Invalid_File_Format;
2137        goto Exit;
2138      }
2139
2140      if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2141        goto Exit;
2142      FT_MEM_COPY( p->font->name, s, slen + 1 );
2143
2144      /* If the font name is an XLFD name, set the spacing to the one in  */
2145      /* the font name.  If there is no spacing fall back on the default. */
2146      error = _bdf_set_default_spacing( p->font, p->opts );
2147      if ( error )
2148        goto Exit;
2149
2150      p->flags |= _BDF_FONT_NAME;
2151
2152      goto Exit;
2153    }
2154
2155    /* Check for the SIZE field. */
2156    if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2157    {
2158      if ( !( p->flags & _BDF_FONT_NAME ) )
2159      {
2160        /* Missing the FONT field. */
2161        FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2162        error = BDF_Err_Missing_Font_Field;
2163        goto Exit;
2164      }
2165
2166      error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
2167      if ( error )
2168        goto Exit;
2169
2170      p->font->point_size   = _bdf_atoul( p->list.field[1], 0, 10 );
2171      p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2172      p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2173
2174      /* Check for the bits per pixel field. */
2175      if ( p->list.used == 5 )
2176      {
2177        unsigned short bitcount, i, shift;
2178
2179
2180        p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2181
2182        /* Only values 1, 2, 4, 8 are allowed. */
2183        shift = p->font->bpp;
2184        bitcount = 0;
2185        for ( i = 0; shift > 0; i++ )
2186        {
2187          if ( shift & 1 )
2188            bitcount = i;
2189          shift >>= 1;
2190        }
2191
2192        shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
2193
2194        if ( p->font->bpp > shift || p->font->bpp != shift )
2195        {
2196          /* select next higher value */
2197          p->font->bpp = (unsigned short)( shift << 1 );
2198          FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
2199        }
2200      }
2201      else
2202        p->font->bpp = 1;
2203
2204      p->flags |= _BDF_SIZE;
2205
2206      goto Exit;
2207    }
2208
2209    error = BDF_Err_Invalid_File_Format;
2210
2211  Exit:
2212    return error;
2213  }
2214
2215
2216  /*************************************************************************/
2217  /*                                                                       */
2218  /* API.                                                                  */
2219  /*                                                                       */
2220  /*************************************************************************/
2221
2222
2223  FT_LOCAL_DEF( FT_Error )
2224  bdf_load_font( FT_Stream       stream,
2225                 FT_Memory       extmemory,
2226                 bdf_options_t*  opts,
2227                 bdf_font_t*    *font )
2228  {
2229    unsigned long  lineno = 0; /* make compiler happy */
2230    _bdf_parse_t   *p;
2231
2232    FT_Memory      memory = extmemory;
2233    FT_Error       error  = BDF_Err_Ok;
2234
2235
2236    if ( FT_NEW( p ) )
2237      goto Exit;
2238
2239    memory    = NULL;
2240    p->opts   = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2241    p->minlb  = 32767;
2242    p->memory = extmemory;  /* only during font creation */
2243
2244    _bdf_list_init( &p->list, extmemory );
2245
2246    error = _bdf_readstream( stream, _bdf_parse_start,
2247                             (void *)p, &lineno );
2248    if ( error )
2249      goto Fail;
2250
2251    if ( p->font != 0 )
2252    {
2253      /* If the font is not proportional, set the font's monowidth */
2254      /* field to the width of the font bounding box.              */
2255      memory = p->font->memory;
2256
2257      if ( p->font->spacing != BDF_PROPORTIONAL )
2258        p->font->monowidth = p->font->bbx.width;
2259
2260      /* If the number of glyphs loaded is not that of the original count, */
2261      /* indicate the difference.                                          */
2262      if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
2263      {
2264        FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2265                    p->font->glyphs_used + p->font->unencoded_used ));
2266        p->font->modified = 1;
2267      }
2268
2269      /* Once the font has been loaded, adjust the overall font metrics if */
2270      /* necessary.                                                        */
2271      if ( p->opts->correct_metrics != 0 &&
2272           ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
2273      {
2274        if ( p->maxrb - p->minlb != p->font->bbx.width )
2275        {
2276          FT_TRACE2(( "bdf_load_font: " ACMSG3,
2277                      p->font->bbx.width, p->maxrb - p->minlb ));
2278          p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2279          p->font->modified  = 1;
2280        }
2281
2282        if ( p->font->bbx.x_offset != p->minlb )
2283        {
2284          FT_TRACE2(( "bdf_load_font: " ACMSG4,
2285                      p->font->bbx.x_offset, p->minlb ));
2286          p->font->bbx.x_offset = p->minlb;
2287          p->font->modified     = 1;
2288        }
2289
2290        if ( p->font->bbx.ascent != p->maxas )
2291        {
2292          FT_TRACE2(( "bdf_load_font: " ACMSG5,
2293                      p->font->bbx.ascent, p->maxas ));
2294          p->font->bbx.ascent = p->maxas;
2295          p->font->modified   = 1;
2296        }
2297
2298        if ( p->font->bbx.descent != p->maxds )
2299        {
2300          FT_TRACE2(( "bdf_load_font: " ACMSG6,
2301                      p->font->bbx.descent, p->maxds ));
2302          p->font->bbx.descent  = p->maxds;
2303          p->font->bbx.y_offset = (short)( -p->maxds );
2304          p->font->modified     = 1;
2305        }
2306
2307        if ( p->maxas + p->maxds != p->font->bbx.height )
2308        {
2309          FT_TRACE2(( "bdf_load_font: " ACMSG7,
2310                      p->font->bbx.height, p->maxas + p->maxds ));
2311          p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
2312        }
2313
2314        if ( p->flags & _BDF_SWIDTH_ADJ )
2315          FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2316      }
2317    }
2318
2319    if ( p->flags & _BDF_START )
2320    {
2321      {
2322        /* The ENDFONT field was never reached or did not exist. */
2323        if ( !( p->flags & _BDF_GLYPHS ) )
2324        {
2325          /* Error happened while parsing header. */
2326          FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2327          error = BDF_Err_Corrupted_Font_Header;
2328          goto Exit;
2329        }
2330        else
2331        {
2332          /* Error happened when parsing glyphs. */
2333          FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2334          error = BDF_Err_Corrupted_Font_Glyphs;
2335          goto Exit;
2336        }
2337      }
2338    }
2339
2340    if ( p->font != 0 )
2341    {
2342      /* Make sure the comments are NULL terminated if they exist. */
2343      memory = p->font->memory;
2344
2345      if ( p->font->comments_len > 0 ) {
2346        if ( FT_RENEW_ARRAY( p->font->comments,
2347                             p->font->comments_len,
2348                             p->font->comments_len + 1 ) )
2349          goto Fail;
2350
2351        p->font->comments[p->font->comments_len] = 0;
2352      }
2353    }
2354    else if ( error == BDF_Err_Ok )
2355      error = BDF_Err_Invalid_File_Format;
2356
2357    *font = p->font;
2358
2359  Exit:
2360    if ( p )
2361    {
2362      _bdf_list_done( &p->list );
2363
2364      memory = extmemory;
2365
2366      FT_FREE( p );
2367    }
2368
2369    return error;
2370
2371  Fail:
2372    bdf_free_font( p->font );
2373
2374    memory = extmemory;
2375
2376    FT_FREE( p->font );
2377
2378    goto Exit;
2379  }
2380
2381
2382  FT_LOCAL_DEF( void )
2383  bdf_free_font( bdf_font_t*  font )
2384  {
2385    bdf_property_t*  prop;
2386    unsigned long    i;
2387    bdf_glyph_t*     glyphs;
2388    FT_Memory        memory;
2389
2390
2391    if ( font == 0 )
2392      return;
2393
2394    memory = font->memory;
2395
2396    FT_FREE( font->name );
2397
2398    /* Free up the internal hash table of property names. */
2399    if ( font->internal )
2400    {
2401      hash_free( (hashtable *)font->internal, memory );
2402      FT_FREE( font->internal );
2403    }
2404
2405    /* Free up the comment info. */
2406    FT_FREE( font->comments );
2407
2408    /* Free up the properties. */
2409    for ( i = 0; i < font->props_size; i++ )
2410    {
2411      if ( font->props[i].format == BDF_ATOM )
2412        FT_FREE( font->props[i].value.atom );
2413    }
2414
2415    FT_FREE( font->props );
2416
2417    /* Free up the character info. */
2418    for ( i = 0, glyphs = font->glyphs;
2419          i < font->glyphs_used; i++, glyphs++ )
2420    {
2421      FT_FREE( glyphs->name );
2422      FT_FREE( glyphs->bitmap );
2423    }
2424
2425    for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2426          i++, glyphs++ )
2427    {
2428      FT_FREE( glyphs->name );
2429      FT_FREE( glyphs->bitmap );
2430    }
2431
2432    FT_FREE( font->glyphs );
2433    FT_FREE( font->unencoded );
2434
2435    /* Free up the overflow storage if it was used. */
2436    for ( i = 0, glyphs = font->overflow.glyphs;
2437          i < font->overflow.glyphs_used; i++, glyphs++ )
2438    {
2439      FT_FREE( glyphs->name );
2440      FT_FREE( glyphs->bitmap );
2441    }
2442
2443    FT_FREE( font->overflow.glyphs );
2444
2445    /* bdf_cleanup */
2446    hash_free( &(font->proptbl), memory );
2447
2448    /* Free up the user defined properties. */
2449    for (prop = font->user_props, i = 0;
2450         i < font->nuser_props; i++, prop++ )
2451    {
2452      FT_FREE( prop->name );
2453      if ( prop->format == BDF_ATOM )
2454        FT_FREE( prop->value.atom );
2455    }
2456
2457    FT_FREE( font->user_props );
2458
2459    /* FREE( font ); */ /* XXX Fixme */
2460  }
2461
2462
2463  FT_LOCAL_DEF( bdf_property_t * )
2464  bdf_get_font_property( bdf_font_t*  font,
2465                         const char*  name )
2466  {
2467    hashnode  hn;
2468
2469
2470    if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
2471      return 0;
2472
2473    hn = hash_lookup( name, (hashtable *)font->internal );
2474
2475    return hn ? ( font->props + (unsigned long)hn->data ) : 0;
2476  }
2477
2478
2479/* END */
Note: See TracBrowser for help on using the repository browser.