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