1 rizwank 1.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, 59 Temple Place - Suite 330,
22 rizwank 1.1 * Boston, MA 02111-1307, 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 rizwank 1.1 };
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 rizwank 1.1 {"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 rizwank 1.1 {"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 rizwank 1.1 {"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 rizwank 1.1 {"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 rizwank 1.1 /*
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 rizwank 1.1
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 rizwank 1.1 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 rizwank 1.1 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 rizwank 1.1 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 rizwank 1.1 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 rizwank 1.1 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 rizwank 1.1 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 rizwank 1.1 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 rizwank 1.1 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 rizwank 1.1 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 rizwank 1.1 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 rizwank 1.1 {
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 rizwank 1.1 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 rizwank 1.1 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 rizwank 1.1 /* 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 rizwank 1.1
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 rizwank 1.1
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 rizwank 1.1 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 rizwank 1.1
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 rizwank 1.1 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 rizwank 1.1
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 rizwank 1.1 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 rizwank 1.1 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 rizwank 1.1 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 rizwank 1.1 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 rizwank 1.1 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 rizwank 1.1 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 rizwank 1.1 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 rizwank 1.1 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 rizwank 1.1 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 rizwank 1.1 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 rizwank 1.1 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 rizwank 1.1 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 rizwank 1.1
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 rizwank 1.1 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 rizwank 1.1 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 rizwank 1.1 {
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 rizwank 1.1
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 rizwank 1.1 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 rizwank 1.1 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 rizwank 1.1
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 }
|