3 * Copyright (c) 1995-1998 Markku Rossi.
5 * Author: Markku Rossi <mtr@iki.fi>
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.
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.
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/>.
31 ((ch) == ' ' || (ch) == '\n' || (ch) == '\r' || (ch) == '\t' || (ch) == ';')
33 #define GET_VALUE(typenum) get_type (handle, ctx, (typenum), &node)
38 char token[1024]; /* maximum line length is 255, this should be
40 unsigned int tokenlen; /* length of the token */
43 typedef struct parse_ctx_st ParseCtx;
50 * The AFM keys. This array must be kept sorted because keys are
51 * searched by using binary search.
53 static struct keyname_st
59 {"Ascender", kAscender},
61 {"AxisLabel", kAxisLabel},
62 {"AxisType", kAxisType},
64 {"BlendAxisTypes", kBlendAxisTypes},
65 {"BlendDesignMap", kBlendDesignMap},
66 {"BlendDesignPositions", kBlendDesignPositions},
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},
104 {"MappingScheme", kMappingScheme},
105 {"Masters", kMasters},
106 {"MetricsSets", kMetricsSets},
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},
126 {"VVector", kVVector},
127 {"Version", kVersion},
138 {"WeightVector", kWeightVector},
139 {"XHeight", kXHeight},
144 #define NUM_KEYS (sizeof (keynames) / sizeof (struct keyname_st) - 1)
147 * Prototypes for static functions.
150 /* Throw parse error <error>. Never returns. */
151 static void parse_error ___P ((AFMHandle handle, AFMError error));
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,
161 static void read_kern_pairs ___P ((AFMHandle handle, ParseCtx *ctx,
163 static void read_track_kerns ___P ((AFMHandle handle, ParseCtx *ctx,
165 static void read_composites ___P ((AFMHandle handle, ParseCtx *ctx,
173 afm_parse_file (AFMHandle handle, const char *filename, AFMFont font)
178 ParseCtx *ctx = &context;
179 int wd = 0; /* Writing direction. */
182 ctx->fp = fopen (filename, "r");
184 parse_error (handle, SYSERROR (AFM_ERROR_FILE_IO));
186 /* Check that file is really an AFM file. */
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;
197 get_key (handle, ctx, &key);
201 (void) get_line_token (handle, ctx);
205 /* File structure. */
207 case kStartFontMetrics:
208 GET_VALUE (AFM_TYPE_NUMBER);
209 font->version = node.u.number;
212 case kEndFontMetrics:
216 case kStartCompFontMetrics:
217 case kEndCompFontMetrics:
218 case kStartMasterFontMetrics:
219 case kEndMasterFontMetrics:
220 parse_error (handle, AFM_ERROR_UNSUPPORTED_FORMAT);
223 /* Global font information. */
225 GET_VALUE (AFM_TYPE_STRING);
226 font->global_info.FontName = node.u.string;
230 GET_VALUE (AFM_TYPE_STRING);
231 font->global_info.FullName = node.u.string;
235 GET_VALUE (AFM_TYPE_STRING);
236 font->global_info.FamilyName = node.u.string;
240 GET_VALUE (AFM_TYPE_STRING);
241 font->global_info.Weight = node.u.string;
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;
256 GET_VALUE (AFM_TYPE_STRING);
257 font->global_info.Version = node.u.string;
261 GET_VALUE (AFM_TYPE_STRING);
262 font->global_info.Notice = node.u.string;
265 case kEncodingScheme:
266 GET_VALUE (AFM_TYPE_STRING);
267 font->global_info.EncodingScheme = node.u.string;
271 GET_VALUE (AFM_TYPE_INTEGER);
272 font->global_info.MappingScheme = node.u.integer;
276 GET_VALUE (AFM_TYPE_INTEGER);
277 font->global_info.EscChar = node.u.integer;
281 GET_VALUE (AFM_TYPE_STRING);
282 font->global_info.CharacterSet = node.u.string;
286 GET_VALUE (AFM_TYPE_INTEGER);
287 font->global_info.Characters = node.u.integer;
291 GET_VALUE (AFM_TYPE_BOOLEAN);
292 font->global_info.IsBaseFont = node.u.boolean;
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;
303 GET_VALUE (AFM_TYPE_BOOLEAN);
304 font->global_info.IsFixedV = node.u.boolean;
308 GET_VALUE (AFM_TYPE_NUMBER);
309 font->global_info.CapHeight = node.u.number;
313 GET_VALUE (AFM_TYPE_NUMBER);
314 font->global_info.XHeight = node.u.number;
318 GET_VALUE (AFM_TYPE_NUMBER);
319 font->global_info.Ascender = node.u.number;
323 GET_VALUE (AFM_TYPE_NUMBER);
324 font->global_info.Descender = node.u.number;
327 /* Writing directions. */
328 case kStartDirection:
329 GET_VALUE (AFM_TYPE_INTEGER);
331 font->writing_direction_metrics[wd].is_valid = AFMTrue;
334 case kUnderlinePosition:
335 GET_VALUE (AFM_TYPE_NUMBER);
336 font->writing_direction_metrics[wd].UnderlinePosition
340 case kUnderlineThickness:
341 GET_VALUE (AFM_TYPE_NUMBER);
342 font->writing_direction_metrics[wd].UnderlineThickness
347 GET_VALUE (AFM_TYPE_NUMBER);
348 font->writing_direction_metrics[wd].ItalicAngle = node.u.number;
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;
359 GET_VALUE (AFM_TYPE_BOOLEAN);
360 font->writing_direction_metrics[wd].IsFixedPitch = node.u.boolean;
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);
377 read_character_metrics (handle, ctx, font);
384 case kStartKernPairs:
385 if (font->info_level & AFM_I_KERN_PAIRS)
387 GET_VALUE (AFM_TYPE_INTEGER);
388 font->num_kern_pairs = node.u.integer;
390 (AFMPairWiseKerning *) calloc (font->num_kern_pairs + 1,
391 sizeof (AFMPairWiseKerning));
392 if (font->kern_pairs == NULL)
393 parse_error (handle, AFM_ERROR_MEMORY);
395 read_kern_pairs (handle, ctx, font);
401 (void) get_line_token (handle, ctx);
402 get_key (handle, ctx, &key);
404 while (key != kEndKernPairs);
408 case kStartTrackKern:
409 if (font->info_level & AFM_I_TRACK_KERNS)
411 GET_VALUE (AFM_TYPE_INTEGER);
412 font->num_track_kerns = node.u.integer;
414 = (AFMTrackKern *) calloc (font->num_track_kerns + 1,
415 sizeof (AFMTrackKern));
416 if (font->track_kerns == NULL)
417 parse_error (handle, AFM_ERROR_MEMORY);
419 read_track_kerns (handle, ctx, font);
425 (void) get_line_token (handle, ctx);
426 get_key (handle, ctx, &key);
428 while (key != kEndTrackKern);
435 /* Composite Character Data. */
436 case kStartComposites:
437 if (font->info_level & AFM_I_COMPOSITES)
439 GET_VALUE (AFM_TYPE_INTEGER);
440 font->num_composites = node.u.integer;
442 = (AFMComposite *) calloc (font->num_composites + 1,
443 sizeof (AFMComposite));
444 if (font->composites == NULL)
445 parse_error (handle, AFM_ERROR_MEMORY);
447 read_composites (handle, ctx, font);
453 (void) get_line_token (handle, ctx);
454 get_key (handle, ctx, &key);
456 while (key != kEndComposites);
467 /* Check post conditions. */
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;
474 /* Undef character. */
475 if (!strhash_get (font->private->fontnames, "space", 5,
476 (void *) font->private->undef))
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];
484 if (font->writing_direction_metrics[0].is_valid
485 && font->writing_direction_metrics[0].IsFixedPitch)
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;
493 if (font->writing_direction_metrics[1].is_valid
494 && font->writing_direction_metrics[1].IsFixedPitch)
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;
509 parse_error (AFMHandle handle, AFMError error)
511 handle->parse_error = error;
512 longjmp (handle->jmpbuf, 1);
514 /* If this is reached, then all is broken. */
515 fprintf (stderr, "AFM: fatal internal longjmp() error.\n");
521 get_token (AFMHandle handle, ParseCtx *ctx)
526 /* Skip the leading whitespace. */
527 while ((ch = getc (ctx->fp)) != EOF)
534 ungetc (ch, ctx->fp);
537 for (i = 0, ch = getc (ctx->fp);
538 i < sizeof (ctx->token) && ch != EOF && !ISSPACE (ch);
539 i++, ch = getc (ctx->fp))
542 if (i >= sizeof (ctx->token))
543 /* Line is too long, this is against AFM specification. */
544 parse_error (handle, AFM_ERROR_SYNTAX);
546 ctx->token[i] = '\0';
554 get_line_token (AFMHandle handle, ParseCtx *ctx)
558 /* Skip the leading whitespace. */
559 while ((ch = getc (ctx->fp)) != EOF)
566 ungetc (ch, ctx->fp);
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))
574 if (i >= sizeof (ctx->token))
575 parse_error (handle, AFM_ERROR_SYNTAX);
577 /* Skip all trailing whitespace. */
578 for (i--; i >= 0 && ISSPACE (ctx->token[i]); i--)
582 ctx->token[i] = '\0';
590 match_key (char *key)
593 int upper = NUM_KEYS;
594 int midpoint, cmpvalue;
595 AFMBoolean found = AFMFalse;
597 while ((upper >= lower) && !found)
599 midpoint = (lower + upper) / 2;
600 if (keynames[midpoint].name == NULL)
603 cmpvalue = strcmp (key, keynames[midpoint].name);
606 else if (cmpvalue < 0)
607 upper = midpoint - 1;
609 lower = midpoint + 1;
613 return keynames[midpoint].key;
620 get_key (AFMHandle handle, ParseCtx *ctx, AFMKey *key_return)
627 if (!get_token (handle, ctx))
628 /* Unexpected EOF. */
629 parse_error (handle, AFM_ERROR_SYNTAX);
631 key = match_key (ctx->token);
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);
648 /* Reader for AFM types. */
650 get_type (AFMHandle handle, ParseCtx *ctx, int type, AFMNode *type_return)
656 case AFM_TYPE_STRING:
657 if (!get_line_token (handle, ctx))
658 parse_error (handle, AFM_ERROR_SYNTAX);
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);
664 memcpy (type_return->u.string, ctx->token, ctx->tokenlen);
668 if (!get_token (handle, ctx))
669 parse_error (handle, AFM_ERROR_SYNTAX);
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);
675 memcpy (type_return->u.name, ctx->token, ctx->tokenlen);
678 case AFM_TYPE_NUMBER:
679 if (!get_token (handle, ctx))
680 parse_error (handle, AFM_ERROR_SYNTAX);
682 memcpy (buf, ctx->token, ctx->tokenlen);
683 buf[ctx->tokenlen] = '\0';
684 type_return->u.number = atof (buf);
687 case AFM_TYPE_INTEGER:
688 if (!get_token (handle, ctx))
689 parse_error (handle, AFM_ERROR_SYNTAX);
691 memcpy (buf, ctx->token, ctx->tokenlen);
692 buf[ctx->tokenlen] = '\0';
693 type_return->u.integer = atoi (buf);
697 fprintf (stderr, "Array types not implemented yet.\n");
701 case AFM_TYPE_BOOLEAN:
702 if (!get_token (handle, ctx))
703 parse_error (handle, AFM_ERROR_SYNTAX);
705 memcpy (buf, ctx->token, ctx->tokenlen);
706 buf[ctx->tokenlen] = '\0';
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;
713 parse_error (handle, AFM_ERROR_SYNTAX);
717 fprintf (stderr, "get_type(): illegal type %d\n", type_return->type);
725 read_character_metrics (AFMHandle handle, ParseCtx *ctx, AFMFont font)
729 AFMIndividualCharacterMetrics *cm = NULL;
736 get_key (handle, ctx, &key);
744 if (i >= font->num_character_metrics)
745 parse_error (handle, AFM_ERROR_SYNTAX);
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;
760 GET_VALUE (AFM_TYPE_NUMBER);
761 cm->w0x = node.u.number;
766 GET_VALUE (AFM_TYPE_NUMBER);
767 cm->w1x = node.u.number;
773 GET_VALUE (AFM_TYPE_NUMBER);
774 cm->w0y = node.u.number;
779 GET_VALUE (AFM_TYPE_NUMBER);
780 cm->w1y = node.u.number;
786 GET_VALUE (AFM_TYPE_NUMBER);
787 cm->w0x = node.u.number;
788 GET_VALUE (AFM_TYPE_NUMBER);
789 cm->w0y = node.u.number;
793 GET_VALUE (AFM_TYPE_NUMBER);
794 cm->w1x = node.u.number;
795 GET_VALUE (AFM_TYPE_NUMBER);
796 cm->w1y = node.u.number;
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;
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);
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;
826 /* XXX Skip ligatures. */
827 get_line_token (handle, ctx);
830 case kEndCharMetrics:
831 if (i != font->num_character_metrics - 1)
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...
839 font->num_character_metrics = i + 1;
846 parse_error (handle, AFM_ERROR_SYNTAX);
854 read_kern_pairs (AFMHandle handle, ParseCtx *ctx, AFMFont font)
858 AFMPairWiseKerning *kp;
861 for (i = 0; i < font->num_kern_pairs; i++)
863 kp = &font->kern_pairs[i];
864 get_key (handle, ctx, &key);
871 GET_VALUE (AFM_TYPE_NAME);
872 kp->name1 = node.u.name;
874 GET_VALUE (AFM_TYPE_NAME);
875 kp->name2 = node.u.name;
877 GET_VALUE (AFM_TYPE_NUMBER);
882 kp->kx = node.u.number;
883 GET_VALUE (AFM_TYPE_NUMBER);
884 kp->ky = node.u.number;
888 kp->kx = node.u.number;
893 kp->ky = node.u.number;
898 fprintf (stderr, "AFM: fatal corruption\n");
909 parse_error (handle, AFM_ERROR_SYNTAX);
915 get_key (handle, ctx, &key);
916 if (key != kEndKernPairs)
917 parse_error (handle, AFM_ERROR_SYNTAX);
922 read_track_kerns (AFMHandle handle, ParseCtx *ctx, AFMFont font)
929 for (i = 0; i < font->num_kern_pairs; i++)
931 tk = &font->track_kerns[i];
932 get_key (handle, ctx, &key);
934 /* TrackKern degree min-ptsize min-kern max-ptrsize max-kern */
936 if (key != kTrackKern)
937 parse_error (handle, AFM_ERROR_SYNTAX);
939 GET_VALUE (AFM_TYPE_INTEGER);
940 tk->degree = node.u.integer;
942 GET_VALUE (AFM_TYPE_NUMBER);
943 tk->min_ptsize = node.u.number;
945 GET_VALUE (AFM_TYPE_NUMBER);
946 tk->min_kern = node.u.number;
948 GET_VALUE (AFM_TYPE_NUMBER);
949 tk->max_ptsize = node.u.number;
951 GET_VALUE (AFM_TYPE_NUMBER);
952 tk->max_kern = node.u.number;
956 get_key (handle, ctx, &key);
957 if (key != kEndTrackKern)
958 parse_error (handle, AFM_ERROR_SYNTAX);
963 read_composites (AFMHandle handle, ParseCtx *ctx, AFMFont font)
970 for (i = 0; i < font->num_composites; i++)
972 cm = &font->composites[i];
973 get_key (handle, ctx, &key);
976 parse_error (handle, AFM_ERROR_SYNTAX);
978 GET_VALUE (AFM_TYPE_NAME);
979 cm->name = node.u.name;
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);
986 GET_VALUE (AFM_TYPE_INTEGER);
987 cm->num_components = node.u.integer;
989 = (AFMCompositeComponent *) calloc (cm->num_components + 1,
990 sizeof (AFMCompositeComponent));
992 /* Read composite components. */
993 for (j = 0; j < cm->num_components; j++)
996 get_key (handle, ctx, &key);
998 parse_error (handle, AFM_ERROR_SYNTAX);
1002 GET_VALUE (AFM_TYPE_NAME);
1003 cm->components[j].name = node.u.name;
1005 GET_VALUE (AFM_TYPE_NUMBER);
1006 cm->components[j].deltax = node.u.number;
1008 GET_VALUE (AFM_TYPE_NUMBER);
1009 cm->components[j].deltay = node.u.number;
1013 /* Get end token. */
1014 get_key (handle, ctx, &key);
1015 if (key != kEndComposites)
1016 parse_error (handle, AFM_ERROR_SYNTAX);