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