8c995adc3c74a67e892c087b9e825da91b91c8a7
[enscript.git] / afmlib / afmparse.c
1 /*
2  * Parse AFM files.
3  * Copyright (c) 1995-1998 Markku Rossi.
4  *
5  * Author: Markku Rossi <mtr@iki.fi>
6  */
7
8 /*
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2, or (at your option)
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; see the file COPYING.  If not, write to
21  * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24
25 #include "afmint.h"
26 #include "afm.h"
27
28 /*
29  * Definitions.
30  */
31
32 #define ISSPACE(ch) \
33   ((ch) == ' ' || (ch) == '\n' || (ch) == '\r' || (ch) == '\t' || (ch) == ';')
34
35 #define GET_VALUE(typenum) get_type (handle, ctx, (typenum), &node)
36
37 struct parse_ctx_st
38 {
39   FILE *fp;
40   char token[1024];             /* maximum line length is 255, this should be
41                                    enought */
42   unsigned int tokenlen;        /* length of the token */
43 };
44
45 typedef struct parse_ctx_st ParseCtx;
46
47 /*
48  * Static variables.
49  */
50
51 /*
52  * The AFM keys.  This array must be kept sorted because keys are
53  * searched by using binary search.
54  */
55 static struct keyname_st
56 {
57   char *name;
58   AFMKey key;
59 } keynames[] =
60 {
61   {"Ascender",                  kAscender},
62   {"Axes",                      kAxes},
63   {"AxisLabel",                 kAxisLabel},
64   {"AxisType",                  kAxisType},
65   {"B",                         kB},
66   {"BlendAxisTypes",            kBlendAxisTypes},
67   {"BlendDesignMap",            kBlendDesignMap},
68   {"BlendDesignPositions",      kBlendDesignPositions},
69   {"C",                         kC},
70   {"CC",                        kCC},
71   {"CH",                        kCH},
72   {"CapHeight",                 kCapHeight},
73   {"CharWidth",                 kCharWidth},
74   {"CharacterSet",              kCharacterSet},
75   {"Characters",                kCharacters},
76   {"Comment",                   kComment},
77   {"Descendents",               kDescendents},
78   {"Descender",                 kDescender},
79   {"EncodingScheme",            kEncodingScheme},
80   {"EndAxis",                   kEndAxis},
81   {"EndCharMetrics",            kEndCharMetrics},
82   {"EndCompFontMetrics",        kEndCompFontMetrics},
83   {"EndComposites",             kEndComposites},
84   {"EndDescendent",             kEndDescendent},
85   {"EndDirection",              kEndDirection},
86   {"EndFontMetrics",            kEndFontMetrics},
87   {"EndKernData",               kEndKernData},
88   {"EndKernPairs",              kEndKernPairs},
89   {"EndMaster",                 kEndMaster},
90   {"EndMasterFontMetrics",      kEndMasterFontMetrics},
91   {"EndTrackKern",              kEndTrackKern},
92   {"EscChar",                   kEscChar},
93   {"FamilyName",                kFamilyName},
94   {"FontBBox",                  kFontBBox},
95   {"FontName",                  kFontName},
96   {"FullName",                  kFullName},
97   {"IsBaseFont",                kIsBaseFont},
98   {"IsFixedPitch",              kIsFixedPitch},
99   {"IsFixedV",                  kIsFixedV},
100   {"ItalicAngle",               kItalicAngle},
101   {"KP",                        kKP},
102   {"KPH",                       kKPH},
103   {"KPX",                       kKPX},
104   {"KPY",                       kKPY},
105   {"L",                         kL},
106   {"MappingScheme",             kMappingScheme},
107   {"Masters",                   kMasters},
108   {"MetricsSets",               kMetricsSets},
109   {"N",                         kN},
110   {"Notice",                    kNotice},
111   {"PCC",                       kPCC},
112   {"StartAxis",                 kStartAxis},
113   {"StartCharMetrics",          kStartCharMetrics},
114   {"StartCompFontMetrics",      kStartCompFontMetrics},
115   {"StartComposites",           kStartComposites},
116   {"StartDescendent",           kStartDescendent},
117   {"StartDirection",            kStartDirection},
118   {"StartFontMetrics",          kStartFontMetrics},
119   {"StartKernData",             kStartKernData},
120   {"StartKernPairs",            kStartKernPairs},
121   {"StartMaster",               kStartMaster},
122   {"StartMasterFontMetrics",    kStartMasterFontMetrics},
123   {"StartTrackKern",            kStartTrackKern},
124   {"TrackKern",                 kTrackKern},
125   {"UnderlinePosition",         kUnderlinePosition},
126   {"UnderlineThickness",        kUnderlineThickness},
127   {"VV",                        kVV},
128   {"VVector",                   kVVector},
129   {"Version",                   kVersion},
130   {"W",                         kW},
131   {"W0",                        kW0},
132   {"W0X",                       kW0X},
133   {"W0Y",                       kW0Y},
134   {"W1",                        kW1},
135   {"W1X",                       kW1X},
136   {"W1Y",                       kW1Y},
137   {"WX",                        kWX},
138   {"WY",                        kWY},
139   {"Weight",                    kWeight},
140   {"WeightVector",              kWeightVector},
141   {"XHeight",                   kXHeight},
142
143   {NULL, 0},
144 };
145
146 #define NUM_KEYS (sizeof (keynames) / sizeof (struct keyname_st) - 1)
147
148 /*
149  * Prototypes for static functions.
150  */
151
152 /* Throw parse error <error>.  Never returns. */
153 static void parse_error ___P ((AFMHandle handle, AFMError error));
154
155 static int get_token ___P ((AFMHandle handle, ParseCtx *ctx));
156 static int get_line_token ___P ((AFMHandle handle, ParseCtx *ctx));
157 static void get_key ___P ((AFMHandle handle, ParseCtx *ctx,
158                            AFMKey *key_return));
159 static void get_type ___P ((AFMHandle handle, ParseCtx *ctx, int type,
160                             AFMNode *type_return));
161 static void read_character_metrics ___P ((AFMHandle handle, ParseCtx *ctx,
162                                           AFMFont font));
163 static void read_kern_pairs ___P ((AFMHandle handle, ParseCtx *ctx,
164                                    AFMFont font));
165 static void read_track_kerns ___P ((AFMHandle handle, ParseCtx *ctx,
166                                     AFMFont font));
167 static void read_composites ___P ((AFMHandle handle, ParseCtx *ctx,
168                                    AFMFont font));
169
170 /*
171  * Global functions.
172  */
173
174 void
175 afm_parse_file (AFMHandle handle, const char *filename, AFMFont font)
176 {
177   AFMKey key;
178   AFMNode node;
179   ParseCtx context;
180   ParseCtx *ctx = &context;
181   int wd = 0;                   /* Writing direction. */
182   int done = 0;
183
184   ctx->fp = fopen (filename, "r");
185   if (ctx->fp == NULL)
186     parse_error (handle, SYSERROR (AFM_ERROR_FILE_IO));
187
188   /* Check that file is really an AFM file. */
189
190   get_key (handle, ctx, &key);
191   if (key != kStartFontMetrics)
192     parse_error (handle, AFM_ERROR_NOT_AFM_FILE);
193   GET_VALUE (AFM_TYPE_NUMBER);
194   font->version = node.u.number;
195
196   /* Parse it. */
197   while (!done)
198     {
199       get_key (handle, ctx, &key);
200       switch (key)
201         {
202         case kComment:
203           (void) get_line_token (handle, ctx);
204           continue;
205           break;
206
207           /* File structure. */
208
209         case kStartFontMetrics:
210           GET_VALUE (AFM_TYPE_NUMBER);
211           font->version = node.u.number;
212           break;
213
214         case kEndFontMetrics:
215           done = 1;
216           break;
217
218         case kStartCompFontMetrics:
219         case kEndCompFontMetrics:
220         case kStartMasterFontMetrics:
221         case kEndMasterFontMetrics:
222           parse_error (handle, AFM_ERROR_UNSUPPORTED_FORMAT);
223           break;
224
225           /* Global font information. */
226         case kFontName:
227           GET_VALUE (AFM_TYPE_STRING);
228           font->global_info.FontName = node.u.string;
229           break;
230
231         case kFullName:
232           GET_VALUE (AFM_TYPE_STRING);
233           font->global_info.FullName = node.u.string;
234           break;
235
236         case kFamilyName:
237           GET_VALUE (AFM_TYPE_STRING);
238           font->global_info.FamilyName = node.u.string;
239           break;
240
241         case kWeight:
242           GET_VALUE (AFM_TYPE_STRING);
243           font->global_info.Weight = node.u.string;
244           break;
245
246         case kFontBBox:
247           GET_VALUE (AFM_TYPE_NUMBER);
248           font->global_info.FontBBox_llx = node.u.number;
249           GET_VALUE (AFM_TYPE_NUMBER);
250           font->global_info.FontBBox_lly = node.u.number;
251           GET_VALUE (AFM_TYPE_NUMBER);
252           font->global_info.FontBBox_urx = node.u.number;
253           GET_VALUE (AFM_TYPE_NUMBER);
254           font->global_info.FontBBox_ury = node.u.number;
255           break;
256
257         case kVersion:
258           GET_VALUE (AFM_TYPE_STRING);
259           font->global_info.Version = node.u.string;
260           break;
261
262         case kNotice:
263           GET_VALUE (AFM_TYPE_STRING);
264           font->global_info.Notice = node.u.string;
265           break;
266
267         case kEncodingScheme:
268           GET_VALUE (AFM_TYPE_STRING);
269           font->global_info.EncodingScheme = node.u.string;
270           break;
271
272         case kMappingScheme:
273           GET_VALUE (AFM_TYPE_INTEGER);
274           font->global_info.MappingScheme = node.u.integer;
275           break;
276
277         case kEscChar:
278           GET_VALUE (AFM_TYPE_INTEGER);
279           font->global_info.EscChar = node.u.integer;
280           break;
281
282         case kCharacterSet:
283           GET_VALUE (AFM_TYPE_STRING);
284           font->global_info.CharacterSet = node.u.string;
285           break;
286
287         case kCharacters:
288           GET_VALUE (AFM_TYPE_INTEGER);
289           font->global_info.Characters = node.u.integer;
290           break;
291
292         case kIsBaseFont:
293           GET_VALUE (AFM_TYPE_BOOLEAN);
294           font->global_info.IsBaseFont = node.u.boolean;
295           break;
296
297         case kVVector:
298           GET_VALUE (AFM_TYPE_NUMBER);
299           font->global_info.VVector_0 = node.u.number;
300           GET_VALUE (AFM_TYPE_NUMBER);
301           font->global_info.VVector_1 = node.u.number;
302           break;
303
304         case kIsFixedV:
305           GET_VALUE (AFM_TYPE_BOOLEAN);
306           font->global_info.IsFixedV = node.u.boolean;
307           break;
308
309         case kCapHeight:
310           GET_VALUE (AFM_TYPE_NUMBER);
311           font->global_info.CapHeight = node.u.number;
312           break;
313
314         case kXHeight:
315           GET_VALUE (AFM_TYPE_NUMBER);
316           font->global_info.XHeight = node.u.number;
317           break;
318
319         case kAscender:
320           GET_VALUE (AFM_TYPE_NUMBER);
321           font->global_info.Ascender = node.u.number;
322           break;
323
324         case kDescender:
325           GET_VALUE (AFM_TYPE_NUMBER);
326           font->global_info.Descender = node.u.number;
327           break;
328
329           /* Writing directions. */
330         case kStartDirection:
331           GET_VALUE (AFM_TYPE_INTEGER);
332           wd = node.u.integer;
333           font->writing_direction_metrics[wd].is_valid = AFMTrue;
334           break;
335
336         case kUnderlinePosition:
337           GET_VALUE (AFM_TYPE_NUMBER);
338           font->writing_direction_metrics[wd].UnderlinePosition
339             = node.u.number;
340           break;
341
342         case kUnderlineThickness:
343           GET_VALUE (AFM_TYPE_NUMBER);
344           font->writing_direction_metrics[wd].UnderlineThickness
345             = node.u.number;
346           break;
347
348         case kItalicAngle:
349           GET_VALUE (AFM_TYPE_NUMBER);
350           font->writing_direction_metrics[wd].ItalicAngle = node.u.number;
351           break;
352
353         case kCharWidth:
354           GET_VALUE (AFM_TYPE_NUMBER);
355           font->writing_direction_metrics[wd].CharWidth_x = node.u.number;
356           GET_VALUE (AFM_TYPE_NUMBER);
357           font->writing_direction_metrics[wd].CharWidth_y = node.u.number;
358           break;
359
360         case kIsFixedPitch:
361           GET_VALUE (AFM_TYPE_BOOLEAN);
362           font->writing_direction_metrics[wd].IsFixedPitch = node.u.boolean;
363           break;
364
365         case kEndDirection:
366           break;
367
368           /* Individual Character Metrics. */
369         case kStartCharMetrics:
370           GET_VALUE (AFM_TYPE_INTEGER);
371           font->num_character_metrics = node.u.integer;
372           font->character_metrics
373             = ((AFMIndividualCharacterMetrics *)
374                calloc (font->num_character_metrics + 1,
375                        sizeof (AFMIndividualCharacterMetrics)));
376           if (font->character_metrics == NULL)
377             parse_error (handle, AFM_ERROR_MEMORY);
378
379           read_character_metrics (handle, ctx, font);
380           break;
381
382           /* Kerning Data. */
383         case kStartKernData:
384           break;
385
386         case kStartKernPairs:
387           if (font->info_level & AFM_I_KERN_PAIRS)
388             {
389               GET_VALUE (AFM_TYPE_INTEGER);
390               font->num_kern_pairs = node.u.integer;
391               font->kern_pairs =
392                 (AFMPairWiseKerning *) calloc (font->num_kern_pairs + 1,
393                                                sizeof (AFMPairWiseKerning));
394               if (font->kern_pairs == NULL)
395                 parse_error (handle, AFM_ERROR_MEMORY);
396
397               read_kern_pairs (handle, ctx, font);
398             }
399           else
400             {
401               do
402                 {
403                   (void) get_line_token (handle, ctx);
404                   get_key (handle, ctx, &key);
405                 }
406               while (key != kEndKernPairs);
407             }
408           break;
409
410         case kStartTrackKern:
411           if (font->info_level & AFM_I_TRACK_KERNS)
412             {
413               GET_VALUE (AFM_TYPE_INTEGER);
414               font->num_track_kerns = node.u.integer;
415               font->track_kerns
416                 = (AFMTrackKern *) calloc (font->num_track_kerns + 1,
417                                            sizeof (AFMTrackKern));
418               if (font->track_kerns == NULL)
419                 parse_error (handle, AFM_ERROR_MEMORY);
420
421               read_track_kerns (handle, ctx, font);
422             }
423           else
424             {
425               do
426                 {
427                   (void) get_line_token (handle, ctx);
428                   get_key (handle, ctx, &key);
429                 }
430               while (key != kEndTrackKern);
431             }
432           break;
433
434         case kEndKernData:
435           break;
436
437           /* Composite Character Data. */
438         case kStartComposites:
439           if (font->info_level & AFM_I_COMPOSITES)
440             {
441               GET_VALUE (AFM_TYPE_INTEGER);
442               font->num_composites = node.u.integer;
443               font->composites
444                 = (AFMComposite *) calloc (font->num_composites + 1,
445                                            sizeof (AFMComposite));
446               if (font->composites == NULL)
447                 parse_error (handle, AFM_ERROR_MEMORY);
448
449               read_composites (handle, ctx, font);
450             }
451           else
452             {
453               do
454                 {
455                   (void) get_line_token (handle, ctx);
456                   get_key (handle, ctx, &key);
457                 }
458               while (key != kEndComposites);
459             }
460           break;
461
462         default:
463           /* Ignore. */
464           break;
465         }
466     }
467   fclose (ctx->fp);
468
469   /* Check post conditions. */
470
471   if (!font->writing_direction_metrics[0].is_valid
472       && !font->writing_direction_metrics[1].is_valid)
473     /* No direction specified, 0 implied. */
474     font->writing_direction_metrics[0].is_valid = AFMTrue;
475
476   /* Undef character. */
477   if (!strhash_get (font->private->fontnames, "space", 5,
478                     (void *) font->private->undef))
479     {
480       /* Character "space" is not defined.  Select the first one. */
481       assert (font->num_character_metrics > 0);
482       font->private->undef = &font->character_metrics[0];
483     }
484
485   /* Fixed pitch. */
486   if (font->writing_direction_metrics[0].is_valid
487       && font->writing_direction_metrics[0].IsFixedPitch)
488     {
489       /* Take one, it doesn't matter which one. */
490       font->writing_direction_metrics[0].CharWidth_x
491         = font->character_metrics[0].w0x;
492       font->writing_direction_metrics[0].CharWidth_y
493         = font->character_metrics[0].w0y;
494     }
495   if (font->writing_direction_metrics[1].is_valid
496       && font->writing_direction_metrics[1].IsFixedPitch)
497     {
498       font->writing_direction_metrics[1].CharWidth_x
499         = font->character_metrics[1].w1x;
500       font->writing_direction_metrics[1].CharWidth_y
501         = font->character_metrics[1].w1y;
502     }
503 }
504
505
506 /*
507  * Static functions.
508  */
509
510 static void
511 parse_error (AFMHandle handle, AFMError error)
512 {
513   handle->parse_error = error;
514   longjmp (handle->jmpbuf, 1);
515
516   /* If this is reached, then all is broken. */
517   fprintf (stderr, "AFM: fatal internal longjmp() error.\n");
518   abort ();
519 }
520
521
522 static int
523 get_token (AFMHandle handle, ParseCtx *ctx)
524 {
525   int ch;
526   int i;
527
528   /* Skip the leading whitespace. */
529   while ((ch = getc (ctx->fp)) != EOF)
530     if (!ISSPACE (ch))
531       break;
532
533   if (ch == EOF)
534     return 0;
535
536   ungetc (ch, ctx->fp);
537
538   /* Get name. */
539   for (i = 0, ch = getc (ctx->fp);
540        i < sizeof (ctx->token) && ch != EOF && !ISSPACE (ch);
541        i++, ch = getc (ctx->fp))
542     ctx->token[i] = ch;
543
544   if (i >= sizeof (ctx->token))
545     /* Line is too long, this is against AFM specification. */
546     parse_error (handle, AFM_ERROR_SYNTAX);
547
548   ctx->token[i] = '\0';
549   ctx->tokenlen = i;
550
551   return 1;
552 }
553
554
555 static int
556 get_line_token (AFMHandle handle, ParseCtx *ctx)
557 {
558   int i, ch;
559
560   /* Skip the leading whitespace. */
561   while ((ch = getc (ctx->fp)) != EOF)
562     if (!ISSPACE (ch))
563       break;
564
565   if (ch == EOF)
566     return 0;
567
568   ungetc (ch, ctx->fp);
569
570   /* Read to the end of the line. */
571   for (i = 0, ch = getc (ctx->fp);
572        i < sizeof (ctx->token) && ch != EOF && ch != '\n';
573        i++, ch = getc (ctx->fp))
574     ctx->token[i] = ch;
575
576   if (i >= sizeof (ctx->token))
577     parse_error (handle, AFM_ERROR_SYNTAX);
578
579   /* Skip all trailing whitespace. */
580   for (i--; i >= 0 && ISSPACE (ctx->token[i]); i--)
581     ;
582   i++;
583
584   ctx->token[i] = '\0';
585   ctx->tokenlen = i;
586
587   return 1;
588 }
589
590
591 static int
592 match_key (char *key)
593 {
594   int lower = 0;
595   int upper = NUM_KEYS;
596   int midpoint, cmpvalue;
597   AFMBoolean found = AFMFalse;
598
599   while ((upper >= lower) && !found)
600     {
601       midpoint = (lower + upper) / 2;
602       if (keynames[midpoint].name == NULL)
603         break;
604
605       cmpvalue = strcmp (key, keynames[midpoint].name);
606       if (cmpvalue == 0)
607         found = AFMTrue;
608       else if (cmpvalue < 0)
609         upper = midpoint - 1;
610       else
611         lower = midpoint + 1;
612     }
613
614   if (found)
615     return keynames[midpoint].key;
616
617   return -1;
618 }
619
620
621 static void
622 get_key (AFMHandle handle, ParseCtx *ctx, AFMKey *key_return)
623 {
624   int key;
625   char msg[256];
626
627   while (1)
628     {
629       if (!get_token (handle, ctx))
630         /* Unexpected EOF. */
631         parse_error (handle, AFM_ERROR_SYNTAX);
632
633       key = match_key (ctx->token);
634       if (key >= 0)
635         {
636           *key_return = key;
637           return;
638         }
639
640       /* No match found.  According to standard, we must skip this key. */
641       sprintf (msg, "skipping key \"%s\"", ctx->token);
642       afm_error (handle, msg);
643       get_line_token (handle, ctx);
644     }
645
646   /* NOTREACHED */
647 }
648
649
650 /* Reader for AFM types. */
651 static void
652 get_type (AFMHandle handle, ParseCtx *ctx, int type, AFMNode *type_return)
653 {
654   char buf[256];
655
656   switch (type)
657     {
658     case AFM_TYPE_STRING:
659       if (!get_line_token (handle, ctx))
660         parse_error (handle, AFM_ERROR_SYNTAX);
661
662       type_return->u.string = (AFMString) calloc (1, ctx->tokenlen + 1);
663       if (type_return->u.string == NULL)
664         parse_error (handle, AFM_ERROR_MEMORY);
665
666       memcpy (type_return->u.string, ctx->token, ctx->tokenlen);
667       break;
668
669     case AFM_TYPE_NAME:
670       if (!get_token (handle, ctx))
671         parse_error (handle, AFM_ERROR_SYNTAX);
672
673       type_return->u.name = (AFMName) calloc (1, ctx->tokenlen + 1);
674       if (type_return->u.string == NULL)
675         parse_error (handle, AFM_ERROR_MEMORY);
676
677       memcpy (type_return->u.name, ctx->token, ctx->tokenlen);
678       break;
679
680     case AFM_TYPE_NUMBER:
681       if (!get_token (handle, ctx))
682         parse_error (handle, AFM_ERROR_SYNTAX);
683
684       memcpy (buf, ctx->token, ctx->tokenlen);
685       buf[ctx->tokenlen] = '\0';
686       type_return->u.number = atof (buf);
687       break;
688
689     case AFM_TYPE_INTEGER:
690       if (!get_token (handle, ctx))
691         parse_error (handle, AFM_ERROR_SYNTAX);
692
693       memcpy (buf, ctx->token, ctx->tokenlen);
694       buf[ctx->tokenlen] = '\0';
695       type_return->u.integer = atoi (buf);
696       break;
697
698     case AFM_TYPE_ARRAY:
699       fprintf (stderr, "Array types not implemented yet.\n");
700       abort ();
701       break;
702
703     case AFM_TYPE_BOOLEAN:
704       if (!get_token (handle, ctx))
705         parse_error (handle, AFM_ERROR_SYNTAX);
706
707       memcpy (buf, ctx->token, ctx->tokenlen);
708       buf[ctx->tokenlen] = '\0';
709
710       if (strcmp (buf, "true") == 0)
711         type_return->u.boolean = AFMTrue;
712       else if (strcmp (buf, "false") == 0)
713         type_return->u.boolean = AFMFalse;
714       else
715         parse_error (handle, AFM_ERROR_SYNTAX);
716       break;
717
718     default:
719       fprintf (stderr, "get_type(): illegal type %d\n", type_return->type);
720       abort ();
721       break;
722     }
723 }
724
725
726 static void
727 read_character_metrics (AFMHandle handle, ParseCtx *ctx, AFMFont font)
728 {
729   int i = 0;
730   AFMNode node;
731   AFMIndividualCharacterMetrics *cm = NULL;
732   AFMKey key;
733   int done = 0;
734   int first = 1;
735
736   while (!done)
737     {
738       get_key (handle, ctx, &key);
739       switch (key)
740         {
741         case kC:
742           if (first)
743             first = 0;
744           else
745             i++;
746           if (i >= font->num_character_metrics)
747             parse_error (handle, AFM_ERROR_SYNTAX);
748
749           cm = &font->character_metrics[i];
750           GET_VALUE (AFM_TYPE_INTEGER);
751           cm->character_code = node.u.integer;
752           if (cm->character_code >= 0 && cm->character_code <= 255)
753             font->encoding[cm->character_code] = cm;
754           break;
755
756         case kCH:
757           printf ("* CH\n");
758           break;
759
760         case kWX:
761         case kW0X:
762           GET_VALUE (AFM_TYPE_NUMBER);
763           cm->w0x = node.u.number;
764           cm->w0y = 0.0;
765           break;
766
767         case kW1X:
768           GET_VALUE (AFM_TYPE_NUMBER);
769           cm->w1x = node.u.number;
770           cm->w1y = 0.0;
771           break;
772
773         case kWY:
774         case kW0Y:
775           GET_VALUE (AFM_TYPE_NUMBER);
776           cm->w0y = node.u.number;
777           cm->w0x = 0.0;
778           break;
779
780         case kW1Y:
781           GET_VALUE (AFM_TYPE_NUMBER);
782           cm->w1y = node.u.number;
783           cm->w1x = 0.0;
784           break;
785
786         case kW:
787         case kW0:
788           GET_VALUE (AFM_TYPE_NUMBER);
789           cm->w0x = node.u.number;
790           GET_VALUE (AFM_TYPE_NUMBER);
791           cm->w0y = node.u.number;
792           break;
793
794         case kW1:
795           GET_VALUE (AFM_TYPE_NUMBER);
796           cm->w1x = node.u.number;
797           GET_VALUE (AFM_TYPE_NUMBER);
798           cm->w1y = node.u.number;
799           break;
800
801         case kVV:
802           GET_VALUE (AFM_TYPE_NUMBER);
803           cm->vv_x = node.u.number;
804           GET_VALUE (AFM_TYPE_NUMBER);
805           cm->vv_y = node.u.number;
806           break;
807
808         case kN:
809           GET_VALUE (AFM_TYPE_NAME);
810           cm->name = node.u.name;
811           if (!strhash_put (font->private->fontnames, cm->name,
812                             strlen (cm->name), cm, NULL))
813             parse_error (handle, AFM_ERROR_MEMORY);
814           break;
815
816         case kB:
817           GET_VALUE (AFM_TYPE_NUMBER);
818           cm->llx = node.u.number;
819           GET_VALUE (AFM_TYPE_NUMBER);
820           cm->lly = node.u.number;
821           GET_VALUE (AFM_TYPE_NUMBER);
822           cm->urx = node.u.number;
823           GET_VALUE (AFM_TYPE_NUMBER);
824           cm->ury = node.u.number;
825           break;
826
827         case kL:
828           /* XXX Skip ligatures. */
829           get_line_token (handle, ctx);
830           break;
831
832         case kEndCharMetrics:
833           if (i != font->num_character_metrics - 1)
834             {
835               /*
836                * My opinion is that this is a syntax error; the
837                * creator of this AFM file should have been smart
838                * enought to count these character metrics.  Well,
839                * maybe that is too much asked...
840                */
841               font->num_character_metrics = i + 1;
842             }
843
844           done = 1;
845           break;
846
847         default:
848           parse_error (handle, AFM_ERROR_SYNTAX);
849           break;
850         }
851     }
852 }
853
854
855 static void
856 read_kern_pairs (AFMHandle handle, ParseCtx *ctx, AFMFont font)
857 {
858   int i;
859   AFMNode node;
860   AFMPairWiseKerning *kp;
861   AFMKey key;
862
863   for (i = 0; i < font->num_kern_pairs; i++)
864     {
865       kp = &font->kern_pairs[i];
866       get_key (handle, ctx, &key);
867
868       switch (key)
869         {
870         case kKP:
871         case kKPX:
872         case kKPY:
873           GET_VALUE (AFM_TYPE_NAME);
874           kp->name1 = node.u.name;
875
876           GET_VALUE (AFM_TYPE_NAME);
877           kp->name2 = node.u.name;
878
879           GET_VALUE (AFM_TYPE_NUMBER);
880
881           switch (key)
882             {
883             case kKP:
884               kp->kx = node.u.number;
885               GET_VALUE (AFM_TYPE_NUMBER);
886               kp->ky = node.u.number;
887               break;
888
889             case kKPX:
890               kp->kx = node.u.number;
891               kp->ky = 0.0;
892               break;
893
894             case kKPY:
895               kp->ky = node.u.number;
896               kp->kx = 0.0;
897               break;
898
899             default:
900               fprintf (stderr, "AFM: fatal corruption\n");
901               abort ();
902               break;
903             }
904           break;
905
906         case kKPH:
907           /* XXX ignore. */
908           break;
909
910         default:
911           parse_error (handle, AFM_ERROR_SYNTAX);
912           break;
913         }
914     }
915
916   /* Get end token. */
917   get_key (handle, ctx, &key);
918   if (key != kEndKernPairs)
919     parse_error (handle, AFM_ERROR_SYNTAX);
920 }
921
922
923 static void
924 read_track_kerns (AFMHandle handle, ParseCtx *ctx, AFMFont font)
925 {
926   int i;
927   AFMNode node;
928   AFMTrackKern *tk;
929   AFMKey key;
930
931   for (i = 0; i < font->num_kern_pairs; i++)
932     {
933       tk = &font->track_kerns[i];
934       get_key (handle, ctx, &key);
935
936       /* TrackKern degree min-ptsize min-kern max-ptrsize max-kern */
937
938       if (key != kTrackKern)
939         parse_error (handle, AFM_ERROR_SYNTAX);
940
941       GET_VALUE (AFM_TYPE_INTEGER);
942       tk->degree = node.u.integer;
943
944       GET_VALUE (AFM_TYPE_NUMBER);
945       tk->min_ptsize = node.u.number;
946
947       GET_VALUE (AFM_TYPE_NUMBER);
948       tk->min_kern = node.u.number;
949
950       GET_VALUE (AFM_TYPE_NUMBER);
951       tk->max_ptsize = node.u.number;
952
953       GET_VALUE (AFM_TYPE_NUMBER);
954       tk->max_kern = node.u.number;
955     }
956
957   /* Get end token. */
958   get_key (handle, ctx, &key);
959   if (key != kEndTrackKern)
960     parse_error (handle, AFM_ERROR_SYNTAX);
961 }
962
963
964 static void
965 read_composites (AFMHandle handle, ParseCtx *ctx, AFMFont font)
966 {
967   int i, j;
968   AFMNode node;
969   AFMComposite *cm;
970   AFMKey key;
971
972   for (i = 0; i < font->num_composites; i++)
973     {
974       cm = &font->composites[i];
975       get_key (handle, ctx, &key);
976
977       if (key != kCC)
978         parse_error (handle, AFM_ERROR_SYNTAX);
979
980       GET_VALUE (AFM_TYPE_NAME);
981       cm->name = node.u.name;
982
983       /* Create name -> AFMComposite mapping. */
984       if (!strhash_put (font->private->compositenames, cm->name,
985                         strlen (cm->name), cm, NULL))
986         parse_error (handle, AFM_ERROR_MEMORY);
987
988       GET_VALUE (AFM_TYPE_INTEGER);
989       cm->num_components = node.u.integer;
990       cm->components
991         = (AFMCompositeComponent *) calloc (cm->num_components + 1,
992                                             sizeof (AFMCompositeComponent));
993
994       /* Read composite components. */
995       for (j = 0; j < cm->num_components; j++)
996         {
997           /* Read "PCC". */
998           get_key (handle, ctx, &key);
999           if (key != kPCC)
1000             parse_error (handle, AFM_ERROR_SYNTAX);
1001
1002           /* Read values. */
1003
1004           GET_VALUE (AFM_TYPE_NAME);
1005           cm->components[j].name = node.u.name;
1006
1007           GET_VALUE (AFM_TYPE_NUMBER);
1008           cm->components[j].deltax = node.u.number;
1009
1010           GET_VALUE (AFM_TYPE_NUMBER);
1011           cm->components[j].deltay = node.u.number;
1012         }
1013     }
1014
1015   /* Get end token. */
1016   get_key (handle, ctx, &key);
1017   if (key != kEndComposites)
1018     parse_error (handle, AFM_ERROR_SYNTAX);
1019 }