Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3918 Serge 1
/***************************************************************************/
2
/*                                                                         */
3
/*  afmparse.c                                                             */
4
/*                                                                         */
5
/*    AFM parser (body).                                                   */
6
/*                                                                         */
7
/*  Copyright 2006-2010, 2012, 2013 by                                     */
8
/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
9
/*                                                                         */
10
/*  This file is part of the FreeType project, and may only be used,       */
11
/*  modified, and distributed under the terms of the FreeType project      */
12
/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
13
/*  this file you indicate that you have read the license and              */
14
/*  understand and accept it fully.                                        */
15
/*                                                                         */
16
/***************************************************************************/
17
 
18
#include 
19
#include FT_FREETYPE_H
20
#include FT_INTERNAL_DEBUG_H
21
#include FT_INTERNAL_POSTSCRIPT_AUX_H
22
 
23
#include "afmparse.h"
24
#include "psconv.h"
25
 
26
#include "psauxerr.h"
27
 
28
 
29
/***************************************************************************/
30
/*                                                                         */
31
/*    AFM_Stream                                                           */
32
/*                                                                         */
33
/* The use of AFM_Stream is largely inspired by parseAFM.[ch] from t1lib.  */
34
/*                                                                         */
35
/*                                                                         */
36
 
37
  enum
38
  {
39
    AFM_STREAM_STATUS_NORMAL,
40
    AFM_STREAM_STATUS_EOC,
41
    AFM_STREAM_STATUS_EOL,
42
    AFM_STREAM_STATUS_EOF
43
  };
44
 
45
 
46
  typedef struct  AFM_StreamRec_
47
  {
48
    FT_Byte*  cursor;
49
    FT_Byte*  base;
50
    FT_Byte*  limit;
51
 
52
    FT_Int    status;
53
 
54
  } AFM_StreamRec;
55
 
56
 
57
#ifndef EOF
58
#define EOF -1
59
#endif
60
 
61
 
62
  /* this works because empty lines are ignored */
63
#define AFM_IS_NEWLINE( ch )  ( (ch) == '\r' || (ch) == '\n' )
64
 
65
#define AFM_IS_EOF( ch )      ( (ch) == EOF  || (ch) == '\x1a' )
66
#define AFM_IS_SPACE( ch )    ( (ch) == ' '  || (ch) == '\t' )
67
 
68
  /* column separator; there is no `column' in the spec actually */
69
#define AFM_IS_SEP( ch )      ( (ch) == ';' )
70
 
71
#define AFM_GETC()                                                       \
72
          ( ( (stream)->cursor < (stream)->limit ) ? *(stream)->cursor++ \
73
                                                   : EOF )
74
 
75
#define AFM_STREAM_KEY_BEGIN( stream )    \
76
          (char*)( (stream)->cursor - 1 )
77
 
78
#define AFM_STREAM_KEY_LEN( stream, key )       \
79
          ( (char*)(stream)->cursor - key - 1 )
80
 
81
#define AFM_STATUS_EOC( stream ) \
82
          ( (stream)->status >= AFM_STREAM_STATUS_EOC )
83
 
84
#define AFM_STATUS_EOL( stream ) \
85
          ( (stream)->status >= AFM_STREAM_STATUS_EOL )
86
 
87
#define AFM_STATUS_EOF( stream ) \
88
          ( (stream)->status >= AFM_STREAM_STATUS_EOF )
89
 
90
 
91
  static int
92
  afm_stream_skip_spaces( AFM_Stream  stream )
93
  {
94
    int  ch = 0;  /* make stupid compiler happy */
95
 
96
 
97
    if ( AFM_STATUS_EOC( stream ) )
98
      return ';';
99
 
100
    while ( 1 )
101
    {
102
      ch = AFM_GETC();
103
      if ( !AFM_IS_SPACE( ch ) )
104
        break;
105
    }
106
 
107
    if ( AFM_IS_NEWLINE( ch ) )
108
      stream->status = AFM_STREAM_STATUS_EOL;
109
    else if ( AFM_IS_SEP( ch ) )
110
      stream->status = AFM_STREAM_STATUS_EOC;
111
    else if ( AFM_IS_EOF( ch ) )
112
      stream->status = AFM_STREAM_STATUS_EOF;
113
 
114
    return ch;
115
  }
116
 
117
 
118
  /* read a key or value in current column */
119
  static char*
120
  afm_stream_read_one( AFM_Stream  stream )
121
  {
122
    char*  str;
123
 
124
 
125
    afm_stream_skip_spaces( stream );
126
    if ( AFM_STATUS_EOC( stream ) )
127
      return NULL;
128
 
129
    str = AFM_STREAM_KEY_BEGIN( stream );
130
 
131
    while ( 1 )
132
    {
133
      int  ch = AFM_GETC();
134
 
135
 
136
      if ( AFM_IS_SPACE( ch ) )
137
        break;
138
      else if ( AFM_IS_NEWLINE( ch ) )
139
      {
140
        stream->status = AFM_STREAM_STATUS_EOL;
141
        break;
142
      }
143
      else if ( AFM_IS_SEP( ch ) )
144
      {
145
        stream->status = AFM_STREAM_STATUS_EOC;
146
        break;
147
      }
148
      else if ( AFM_IS_EOF( ch ) )
149
      {
150
        stream->status = AFM_STREAM_STATUS_EOF;
151
        break;
152
      }
153
    }
154
 
155
    return str;
156
  }
157
 
158
 
159
  /* read a string (i.e., read to EOL) */
160
  static char*
161
  afm_stream_read_string( AFM_Stream  stream )
162
  {
163
    char*  str;
164
 
165
 
166
    afm_stream_skip_spaces( stream );
167
    if ( AFM_STATUS_EOL( stream ) )
168
      return NULL;
169
 
170
    str = AFM_STREAM_KEY_BEGIN( stream );
171
 
172
    /* scan to eol */
173
    while ( 1 )
174
    {
175
      int  ch = AFM_GETC();
176
 
177
 
178
      if ( AFM_IS_NEWLINE( ch ) )
179
      {
180
        stream->status = AFM_STREAM_STATUS_EOL;
181
        break;
182
      }
183
      else if ( AFM_IS_EOF( ch ) )
184
      {
185
        stream->status = AFM_STREAM_STATUS_EOF;
186
        break;
187
      }
188
    }
189
 
190
    return str;
191
  }
192
 
193
 
194
  /*************************************************************************/
195
  /*                                                                       */
196
  /*    AFM_Parser                                                         */
197
  /*                                                                       */
198
  /*                                                                       */
199
 
200
  /* all keys defined in Ch. 7-10 of 5004.AFM_Spec.pdf */
201
  typedef enum  AFM_Token_
202
  {
203
    AFM_TOKEN_ASCENDER,
204
    AFM_TOKEN_AXISLABEL,
205
    AFM_TOKEN_AXISTYPE,
206
    AFM_TOKEN_B,
207
    AFM_TOKEN_BLENDAXISTYPES,
208
    AFM_TOKEN_BLENDDESIGNMAP,
209
    AFM_TOKEN_BLENDDESIGNPOSITIONS,
210
    AFM_TOKEN_C,
211
    AFM_TOKEN_CC,
212
    AFM_TOKEN_CH,
213
    AFM_TOKEN_CAPHEIGHT,
214
    AFM_TOKEN_CHARWIDTH,
215
    AFM_TOKEN_CHARACTERSET,
216
    AFM_TOKEN_CHARACTERS,
217
    AFM_TOKEN_DESCENDER,
218
    AFM_TOKEN_ENCODINGSCHEME,
219
    AFM_TOKEN_ENDAXIS,
220
    AFM_TOKEN_ENDCHARMETRICS,
221
    AFM_TOKEN_ENDCOMPOSITES,
222
    AFM_TOKEN_ENDDIRECTION,
223
    AFM_TOKEN_ENDFONTMETRICS,
224
    AFM_TOKEN_ENDKERNDATA,
225
    AFM_TOKEN_ENDKERNPAIRS,
226
    AFM_TOKEN_ENDTRACKKERN,
227
    AFM_TOKEN_ESCCHAR,
228
    AFM_TOKEN_FAMILYNAME,
229
    AFM_TOKEN_FONTBBOX,
230
    AFM_TOKEN_FONTNAME,
231
    AFM_TOKEN_FULLNAME,
232
    AFM_TOKEN_ISBASEFONT,
233
    AFM_TOKEN_ISCIDFONT,
234
    AFM_TOKEN_ISFIXEDPITCH,
235
    AFM_TOKEN_ISFIXEDV,
236
    AFM_TOKEN_ITALICANGLE,
237
    AFM_TOKEN_KP,
238
    AFM_TOKEN_KPH,
239
    AFM_TOKEN_KPX,
240
    AFM_TOKEN_KPY,
241
    AFM_TOKEN_L,
242
    AFM_TOKEN_MAPPINGSCHEME,
243
    AFM_TOKEN_METRICSSETS,
244
    AFM_TOKEN_N,
245
    AFM_TOKEN_NOTICE,
246
    AFM_TOKEN_PCC,
247
    AFM_TOKEN_STARTAXIS,
248
    AFM_TOKEN_STARTCHARMETRICS,
249
    AFM_TOKEN_STARTCOMPOSITES,
250
    AFM_TOKEN_STARTDIRECTION,
251
    AFM_TOKEN_STARTFONTMETRICS,
252
    AFM_TOKEN_STARTKERNDATA,
253
    AFM_TOKEN_STARTKERNPAIRS,
254
    AFM_TOKEN_STARTKERNPAIRS0,
255
    AFM_TOKEN_STARTKERNPAIRS1,
256
    AFM_TOKEN_STARTTRACKKERN,
257
    AFM_TOKEN_STDHW,
258
    AFM_TOKEN_STDVW,
259
    AFM_TOKEN_TRACKKERN,
260
    AFM_TOKEN_UNDERLINEPOSITION,
261
    AFM_TOKEN_UNDERLINETHICKNESS,
262
    AFM_TOKEN_VV,
263
    AFM_TOKEN_VVECTOR,
264
    AFM_TOKEN_VERSION,
265
    AFM_TOKEN_W,
266
    AFM_TOKEN_W0,
267
    AFM_TOKEN_W0X,
268
    AFM_TOKEN_W0Y,
269
    AFM_TOKEN_W1,
270
    AFM_TOKEN_W1X,
271
    AFM_TOKEN_W1Y,
272
    AFM_TOKEN_WX,
273
    AFM_TOKEN_WY,
274
    AFM_TOKEN_WEIGHT,
275
    AFM_TOKEN_WEIGHTVECTOR,
276
    AFM_TOKEN_XHEIGHT,
277
    N_AFM_TOKENS,
278
    AFM_TOKEN_UNKNOWN
279
 
280
  } AFM_Token;
281
 
282
 
283
  static const char*  const afm_key_table[N_AFM_TOKENS] =
284
  {
285
    "Ascender",
286
    "AxisLabel",
287
    "AxisType",
288
    "B",
289
    "BlendAxisTypes",
290
    "BlendDesignMap",
291
    "BlendDesignPositions",
292
    "C",
293
    "CC",
294
    "CH",
295
    "CapHeight",
296
    "CharWidth",
297
    "CharacterSet",
298
    "Characters",
299
    "Descender",
300
    "EncodingScheme",
301
    "EndAxis",
302
    "EndCharMetrics",
303
    "EndComposites",
304
    "EndDirection",
305
    "EndFontMetrics",
306
    "EndKernData",
307
    "EndKernPairs",
308
    "EndTrackKern",
309
    "EscChar",
310
    "FamilyName",
311
    "FontBBox",
312
    "FontName",
313
    "FullName",
314
    "IsBaseFont",
315
    "IsCIDFont",
316
    "IsFixedPitch",
317
    "IsFixedV",
318
    "ItalicAngle",
319
    "KP",
320
    "KPH",
321
    "KPX",
322
    "KPY",
323
    "L",
324
    "MappingScheme",
325
    "MetricsSets",
326
    "N",
327
    "Notice",
328
    "PCC",
329
    "StartAxis",
330
    "StartCharMetrics",
331
    "StartComposites",
332
    "StartDirection",
333
    "StartFontMetrics",
334
    "StartKernData",
335
    "StartKernPairs",
336
    "StartKernPairs0",
337
    "StartKernPairs1",
338
    "StartTrackKern",
339
    "StdHW",
340
    "StdVW",
341
    "TrackKern",
342
    "UnderlinePosition",
343
    "UnderlineThickness",
344
    "VV",
345
    "VVector",
346
    "Version",
347
    "W",
348
    "W0",
349
    "W0X",
350
    "W0Y",
351
    "W1",
352
    "W1X",
353
    "W1Y",
354
    "WX",
355
    "WY",
356
    "Weight",
357
    "WeightVector",
358
    "XHeight"
359
  };
360
 
361
 
362
  /*
363
   * `afm_parser_read_vals' and `afm_parser_next_key' provide
364
   * high-level operations to an AFM_Stream.  The rest of the
365
   * parser functions should use them without accessing the
366
   * AFM_Stream directly.
367
   */
368
 
369
  FT_LOCAL_DEF( FT_Int )
370
  afm_parser_read_vals( AFM_Parser  parser,
371
                        AFM_Value   vals,
372
                        FT_UInt     n )
373
  {
374
    AFM_Stream  stream = parser->stream;
375
    char*       str;
376
    FT_UInt     i;
377
 
378
 
379
    if ( n > AFM_MAX_ARGUMENTS )
380
      return 0;
381
 
382
    for ( i = 0; i < n; i++ )
383
    {
384
      FT_Offset  len;
385
      AFM_Value  val = vals + i;
386
 
387
 
388
      if ( val->type == AFM_VALUE_TYPE_STRING )
389
        str = afm_stream_read_string( stream );
390
      else
391
        str = afm_stream_read_one( stream );
392
 
393
      if ( !str )
394
        break;
395
 
396
      len = AFM_STREAM_KEY_LEN( stream, str );
397
 
398
      switch ( val->type )
399
      {
400
      case AFM_VALUE_TYPE_STRING:
401
      case AFM_VALUE_TYPE_NAME:
402
        {
403
          FT_Memory  memory = parser->memory;
404
          FT_Error   error;
405
 
406
 
407
          if ( !FT_QALLOC( val->u.s, len + 1 ) )
408
          {
409
            ft_memcpy( val->u.s, str, len );
410
            val->u.s[len] = '\0';
411
          }
412
        }
413
        break;
414
 
415
      case AFM_VALUE_TYPE_FIXED:
416
        val->u.f = PS_Conv_ToFixed( (FT_Byte**)(void*)&str,
417
                                    (FT_Byte*)str + len, 0 );
418
        break;
419
 
420
      case AFM_VALUE_TYPE_INTEGER:
421
        val->u.i = PS_Conv_ToInt( (FT_Byte**)(void*)&str,
422
                                  (FT_Byte*)str + len );
423
        break;
424
 
425
      case AFM_VALUE_TYPE_BOOL:
426
        val->u.b = FT_BOOL( len == 4                      &&
427
                            !ft_strncmp( str, "true", 4 ) );
428
        break;
429
 
430
      case AFM_VALUE_TYPE_INDEX:
431
        if ( parser->get_index )
432
          val->u.i = parser->get_index( str, len, parser->user_data );
433
        else
434
          val->u.i = 0;
435
        break;
436
      }
437
    }
438
 
439
    return i;
440
  }
441
 
442
 
443
  FT_LOCAL_DEF( char* )
444
  afm_parser_next_key( AFM_Parser  parser,
445
                       FT_Bool     line,
446
                       FT_Offset*  len )
447
  {
448
    AFM_Stream  stream = parser->stream;
449
    char*       key    = 0;  /* make stupid compiler happy */
450
 
451
 
452
    if ( line )
453
    {
454
      while ( 1 )
455
      {
456
        /* skip current line */
457
        if ( !AFM_STATUS_EOL( stream ) )
458
          afm_stream_read_string( stream );
459
 
460
        stream->status = AFM_STREAM_STATUS_NORMAL;
461
        key = afm_stream_read_one( stream );
462
 
463
        /* skip empty line */
464
        if ( !key                      &&
465
             !AFM_STATUS_EOF( stream ) &&
466
             AFM_STATUS_EOL( stream )  )
467
          continue;
468
 
469
        break;
470
      }
471
    }
472
    else
473
    {
474
      while ( 1 )
475
      {
476
        /* skip current column */
477
        while ( !AFM_STATUS_EOC( stream ) )
478
          afm_stream_read_one( stream );
479
 
480
        stream->status = AFM_STREAM_STATUS_NORMAL;
481
        key = afm_stream_read_one( stream );
482
 
483
        /* skip empty column */
484
        if ( !key                      &&
485
             !AFM_STATUS_EOF( stream ) &&
486
             AFM_STATUS_EOC( stream )  )
487
          continue;
488
 
489
        break;
490
      }
491
    }
492
 
493
    if ( len )
494
      *len = ( key ) ? (FT_Offset)AFM_STREAM_KEY_LEN( stream, key )
495
                     : 0;
496
 
497
    return key;
498
  }
499
 
500
 
501
  static AFM_Token
502
  afm_tokenize( const char*  key,
503
                FT_Offset    len )
504
  {
505
    int  n;
506
 
507
 
508
    for ( n = 0; n < N_AFM_TOKENS; n++ )
509
    {
510
      if ( *( afm_key_table[n] ) == *key )
511
      {
512
        for ( ; n < N_AFM_TOKENS; n++ )
513
        {
514
          if ( *( afm_key_table[n] ) != *key )
515
            return AFM_TOKEN_UNKNOWN;
516
 
517
          if ( ft_strncmp( afm_key_table[n], key, len ) == 0 )
518
            return (AFM_Token) n;
519
        }
520
      }
521
    }
522
 
523
    return AFM_TOKEN_UNKNOWN;
524
  }
525
 
526
 
527
  FT_LOCAL_DEF( FT_Error )
528
  afm_parser_init( AFM_Parser  parser,
529
                   FT_Memory   memory,
530
                   FT_Byte*    base,
531
                   FT_Byte*    limit )
532
  {
533
    AFM_Stream  stream = NULL;
534
    FT_Error    error;
535
 
536
 
537
    if ( FT_NEW( stream ) )
538
      return error;
539
 
540
    stream->cursor = stream->base = base;
541
    stream->limit  = limit;
542
 
543
    /* don't skip the first line during the first call */
544
    stream->status = AFM_STREAM_STATUS_EOL;
545
 
546
    parser->memory    = memory;
547
    parser->stream    = stream;
548
    parser->FontInfo  = NULL;
549
    parser->get_index = NULL;
550
 
551
    return FT_Err_Ok;
552
  }
553
 
554
 
555
  FT_LOCAL( void )
556
  afm_parser_done( AFM_Parser  parser )
557
  {
558
    FT_Memory  memory = parser->memory;
559
 
560
 
561
    FT_FREE( parser->stream );
562
  }
563
 
564
 
565
  FT_LOCAL_DEF( FT_Error )
566
  afm_parser_read_int( AFM_Parser  parser,
567
                       FT_Int*     aint )
568
  {
569
    AFM_ValueRec  val;
570
 
571
 
572
    val.type = AFM_VALUE_TYPE_INTEGER;
573
 
574
    if ( afm_parser_read_vals( parser, &val, 1 ) == 1 )
575
    {
576
      *aint = val.u.i;
577
 
578
      return FT_Err_Ok;
579
    }
580
    else
581
      return FT_THROW( Syntax_Error );
582
  }
583
 
584
 
585
  static FT_Error
586
  afm_parse_track_kern( AFM_Parser  parser )
587
  {
588
    AFM_FontInfo   fi = parser->FontInfo;
589
    AFM_TrackKern  tk;
590
    char*          key;
591
    FT_Offset      len;
592
    int            n = -1;
593
 
594
 
595
    if ( afm_parser_read_int( parser, &fi->NumTrackKern ) )
596
        goto Fail;
597
 
598
    if ( fi->NumTrackKern )
599
    {
600
      FT_Memory  memory = parser->memory;
601
      FT_Error   error;
602
 
603
 
604
      if ( FT_QNEW_ARRAY( fi->TrackKerns, fi->NumTrackKern ) )
605
        return error;
606
    }
607
 
608
    while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
609
    {
610
      AFM_ValueRec  shared_vals[5];
611
 
612
 
613
      switch ( afm_tokenize( key, len ) )
614
      {
615
      case AFM_TOKEN_TRACKKERN:
616
        n++;
617
 
618
        if ( n >= fi->NumTrackKern )
619
          goto Fail;
620
 
621
        tk = fi->TrackKerns + n;
622
 
623
        shared_vals[0].type = AFM_VALUE_TYPE_INTEGER;
624
        shared_vals[1].type = AFM_VALUE_TYPE_FIXED;
625
        shared_vals[2].type = AFM_VALUE_TYPE_FIXED;
626
        shared_vals[3].type = AFM_VALUE_TYPE_FIXED;
627
        shared_vals[4].type = AFM_VALUE_TYPE_FIXED;
628
        if ( afm_parser_read_vals( parser, shared_vals, 5 ) != 5 )
629
          goto Fail;
630
 
631
        tk->degree     = shared_vals[0].u.i;
632
        tk->min_ptsize = shared_vals[1].u.f;
633
        tk->min_kern   = shared_vals[2].u.f;
634
        tk->max_ptsize = shared_vals[3].u.f;
635
        tk->max_kern   = shared_vals[4].u.f;
636
 
637
        break;
638
 
639
      case AFM_TOKEN_ENDTRACKKERN:
640
      case AFM_TOKEN_ENDKERNDATA:
641
      case AFM_TOKEN_ENDFONTMETRICS:
642
        fi->NumTrackKern = n + 1;
643
        return FT_Err_Ok;
644
 
645
      case AFM_TOKEN_UNKNOWN:
646
        break;
647
 
648
      default:
649
        goto Fail;
650
      }
651
    }
652
 
653
  Fail:
654
    return FT_THROW( Syntax_Error );
655
  }
656
 
657
 
658
#undef  KERN_INDEX
659
#define KERN_INDEX( g1, g2 )  ( ( (FT_ULong)g1 << 16 ) | g2 )
660
 
661
 
662
  /* compare two kerning pairs */
663
  FT_CALLBACK_DEF( int )
664
  afm_compare_kern_pairs( const void*  a,
665
                          const void*  b )
666
  {
667
    AFM_KernPair  kp1 = (AFM_KernPair)a;
668
    AFM_KernPair  kp2 = (AFM_KernPair)b;
669
 
670
    FT_ULong  index1 = KERN_INDEX( kp1->index1, kp1->index2 );
671
    FT_ULong  index2 = KERN_INDEX( kp2->index1, kp2->index2 );
672
 
673
 
674
    if ( index1 > index2 )
675
      return 1;
676
    else if ( index1 < index2 )
677
      return -1;
678
    else
679
      return 0;
680
  }
681
 
682
 
683
  static FT_Error
684
  afm_parse_kern_pairs( AFM_Parser  parser )
685
  {
686
    AFM_FontInfo  fi = parser->FontInfo;
687
    AFM_KernPair  kp;
688
    char*         key;
689
    FT_Offset     len;
690
    int           n = -1;
691
 
692
 
693
    if ( afm_parser_read_int( parser, &fi->NumKernPair ) )
694
      goto Fail;
695
 
696
    if ( fi->NumKernPair )
697
    {
698
      FT_Memory  memory = parser->memory;
699
      FT_Error   error;
700
 
701
 
702
      if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) )
703
        return error;
704
    }
705
 
706
    while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
707
    {
708
      AFM_Token  token = afm_tokenize( key, len );
709
 
710
 
711
      switch ( token )
712
      {
713
      case AFM_TOKEN_KP:
714
      case AFM_TOKEN_KPX:
715
      case AFM_TOKEN_KPY:
716
        {
717
          FT_Int        r;
718
          AFM_ValueRec  shared_vals[4];
719
 
720
 
721
          n++;
722
 
723
          if ( n >= fi->NumKernPair )
724
            goto Fail;
725
 
726
          kp = fi->KernPairs + n;
727
 
728
          shared_vals[0].type = AFM_VALUE_TYPE_INDEX;
729
          shared_vals[1].type = AFM_VALUE_TYPE_INDEX;
730
          shared_vals[2].type = AFM_VALUE_TYPE_INTEGER;
731
          shared_vals[3].type = AFM_VALUE_TYPE_INTEGER;
732
          r = afm_parser_read_vals( parser, shared_vals, 4 );
733
          if ( r < 3 )
734
            goto Fail;
735
 
736
          kp->index1 = shared_vals[0].u.i;
737
          kp->index2 = shared_vals[1].u.i;
738
          if ( token == AFM_TOKEN_KPY )
739
          {
740
            kp->x = 0;
741
            kp->y = shared_vals[2].u.i;
742
          }
743
          else
744
          {
745
            kp->x = shared_vals[2].u.i;
746
            kp->y = ( token == AFM_TOKEN_KP && r == 4 )
747
                      ? shared_vals[3].u.i : 0;
748
          }
749
        }
750
        break;
751
 
752
      case AFM_TOKEN_ENDKERNPAIRS:
753
      case AFM_TOKEN_ENDKERNDATA:
754
      case AFM_TOKEN_ENDFONTMETRICS:
755
        fi->NumKernPair = n + 1;
756
        ft_qsort( fi->KernPairs, fi->NumKernPair,
757
                  sizeof ( AFM_KernPairRec ),
758
                  afm_compare_kern_pairs );
759
        return FT_Err_Ok;
760
 
761
      case AFM_TOKEN_UNKNOWN:
762
        break;
763
 
764
      default:
765
        goto Fail;
766
      }
767
    }
768
 
769
  Fail:
770
    return FT_THROW( Syntax_Error );
771
  }
772
 
773
 
774
  static FT_Error
775
  afm_parse_kern_data( AFM_Parser  parser )
776
  {
777
    FT_Error   error;
778
    char*      key;
779
    FT_Offset  len;
780
 
781
 
782
    while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
783
    {
784
      switch ( afm_tokenize( key, len ) )
785
      {
786
      case AFM_TOKEN_STARTTRACKKERN:
787
        error = afm_parse_track_kern( parser );
788
        if ( error )
789
          return error;
790
        break;
791
 
792
      case AFM_TOKEN_STARTKERNPAIRS:
793
      case AFM_TOKEN_STARTKERNPAIRS0:
794
        error = afm_parse_kern_pairs( parser );
795
        if ( error )
796
          return error;
797
        break;
798
 
799
      case AFM_TOKEN_ENDKERNDATA:
800
      case AFM_TOKEN_ENDFONTMETRICS:
801
        return FT_Err_Ok;
802
 
803
      case AFM_TOKEN_UNKNOWN:
804
        break;
805
 
806
      default:
807
        goto Fail;
808
      }
809
    }
810
 
811
  Fail:
812
    return FT_THROW( Syntax_Error );
813
  }
814
 
815
 
816
  static FT_Error
817
  afm_parser_skip_section( AFM_Parser  parser,
818
                           FT_UInt     n,
819
                           AFM_Token   end_section )
820
  {
821
    char*      key;
822
    FT_Offset  len;
823
 
824
 
825
    while ( n-- > 0 )
826
    {
827
      key = afm_parser_next_key( parser, 1, NULL );
828
      if ( !key )
829
        goto Fail;
830
    }
831
 
832
    while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
833
    {
834
      AFM_Token  token = afm_tokenize( key, len );
835
 
836
 
837
      if ( token == end_section || token == AFM_TOKEN_ENDFONTMETRICS )
838
        return FT_Err_Ok;
839
    }
840
 
841
  Fail:
842
    return FT_THROW( Syntax_Error );
843
  }
844
 
845
 
846
  FT_LOCAL_DEF( FT_Error )
847
  afm_parser_parse( AFM_Parser  parser )
848
  {
849
    FT_Memory     memory = parser->memory;
850
    AFM_FontInfo  fi     = parser->FontInfo;
851
    FT_Error      error  = FT_ERR( Syntax_Error );
852
    char*         key;
853
    FT_Offset     len;
854
    FT_Int        metrics_sets = 0;
855
 
856
 
857
    if ( !fi )
858
      return FT_THROW( Invalid_Argument );
859
 
860
    key = afm_parser_next_key( parser, 1, &len );
861
    if ( !key || len != 16                              ||
862
         ft_strncmp( key, "StartFontMetrics", 16 ) != 0 )
863
      return FT_THROW( Unknown_File_Format );
864
 
865
    while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
866
    {
867
      AFM_ValueRec  shared_vals[4];
868
 
869
 
870
      switch ( afm_tokenize( key, len ) )
871
      {
872
      case AFM_TOKEN_METRICSSETS:
873
        if ( afm_parser_read_int( parser, &metrics_sets ) )
874
          goto Fail;
875
 
876
        if ( metrics_sets != 0 && metrics_sets != 2 )
877
        {
878
          error = FT_THROW( Unimplemented_Feature );
879
 
880
          goto Fail;
881
        }
882
        break;
883
 
884
      case AFM_TOKEN_ISCIDFONT:
885
        shared_vals[0].type = AFM_VALUE_TYPE_BOOL;
886
        if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
887
          goto Fail;
888
 
889
        fi->IsCIDFont = shared_vals[0].u.b;
890
        break;
891
 
892
      case AFM_TOKEN_FONTBBOX:
893
        shared_vals[0].type = AFM_VALUE_TYPE_FIXED;
894
        shared_vals[1].type = AFM_VALUE_TYPE_FIXED;
895
        shared_vals[2].type = AFM_VALUE_TYPE_FIXED;
896
        shared_vals[3].type = AFM_VALUE_TYPE_FIXED;
897
        if ( afm_parser_read_vals( parser, shared_vals, 4 ) != 4 )
898
          goto Fail;
899
 
900
        fi->FontBBox.xMin = shared_vals[0].u.f;
901
        fi->FontBBox.yMin = shared_vals[1].u.f;
902
        fi->FontBBox.xMax = shared_vals[2].u.f;
903
        fi->FontBBox.yMax = shared_vals[3].u.f;
904
        break;
905
 
906
      case AFM_TOKEN_ASCENDER:
907
        shared_vals[0].type = AFM_VALUE_TYPE_FIXED;
908
        if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
909
          goto Fail;
910
 
911
        fi->Ascender = shared_vals[0].u.f;
912
        break;
913
 
914
      case AFM_TOKEN_DESCENDER:
915
        shared_vals[0].type = AFM_VALUE_TYPE_FIXED;
916
        if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
917
          goto Fail;
918
 
919
        fi->Descender = shared_vals[0].u.f;
920
        break;
921
 
922
      case AFM_TOKEN_STARTCHARMETRICS:
923
        {
924
          FT_Int  n = 0;
925
 
926
 
927
          if ( afm_parser_read_int( parser, &n ) )
928
            goto Fail;
929
 
930
          error = afm_parser_skip_section( parser, n,
931
                                           AFM_TOKEN_ENDCHARMETRICS );
932
          if ( error )
933
            return error;
934
        }
935
        break;
936
 
937
      case AFM_TOKEN_STARTKERNDATA:
938
        error = afm_parse_kern_data( parser );
939
        if ( error )
940
          goto Fail;
941
        /* fall through since we only support kern data */
942
 
943
      case AFM_TOKEN_ENDFONTMETRICS:
944
        return FT_Err_Ok;
945
 
946
      default:
947
        break;
948
      }
949
    }
950
 
951
  Fail:
952
    FT_FREE( fi->TrackKerns );
953
    fi->NumTrackKern = 0;
954
 
955
    FT_FREE( fi->KernPairs );
956
    fi->NumKernPair = 0;
957
 
958
    fi->IsCIDFont = 0;
959
 
960
    return error;
961
  }
962
 
963
 
964
/* END */