Clean up output subsystem.
[pspp-builds.git] / src / output / afm.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 2006 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18    02110-1301, USA. */
19
20 #include <config.h>
21 #include "afm.h"
22 #include "c-ctype.h"
23 #include "c-strtod.h"
24 #include <ctype.h>
25 #include <errno.h>
26 #include <stdarg.h>
27 #include <stdbool.h>
28 #include <stdint.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <setjmp.h>
32 #include "error.h"
33 #include "minmax.h"
34 #include <libpspp/pool.h>
35 #include <libpspp/str.h>
36
37 #include "gettext.h"
38 #define _(msgid) gettext (msgid)
39
40 /* A kern pair entry. */
41 struct afm_kern_pair 
42   {
43     struct afm_character *successor; /* Second character. */
44     int adjust;                 /* Adjustment. */
45   };
46
47 /* A ligature. */
48 struct afm_ligature 
49   {
50     struct afm_character *successor; /* Second character. */
51     struct afm_character *ligature;  /* Resulting ligature. */
52   };
53
54 /* How to map between byte strings and character values. */
55 enum mapping_scheme 
56   {
57     MAP_UNKNOWN,                /* Not yet determined. */
58     MAP_ONE_BYTE,               /* 8-bit coding. */
59     MAP_TWO_BYTE,               /* 16-bit coding. */
60     MAP_ESCAPE,                 /* 8-bit coding with escape to change fonts. */
61     MAP_DOUBLE_ESCAPE,          /* 8-bit coding with multiple escapes. */
62     MAP_SHIFT                   /* 8-bit coding with 2 fonts that toggle. */
63   };
64
65 /* AFM file data.  */
66 struct afm
67   {
68     struct pool *pool;          /* Containing pool. */
69     char *findfont_name;        /* Name for PostScript /findfont operator. */
70     int ascent;                 /* Height above the baseline (non-negative). */
71     int descent;                /* Depth below the baseline (non-negative). */
72
73     /* Encoding characters into strings. */
74     enum mapping_scheme mapping; /* Basic mapping scheme. */
75     char escape_char;           /* MAP_ESCAPE only: escape character to use. */
76     char shift_out;             /* MAP_SHIFT only: selects font 0. */
77     char shift_in;              /* MAP_SHIFT only: selects font 1. */
78
79     /* Characters. */
80     struct afm_character *undefined_codes[256];
81     struct afm_character **codes[256];
82     struct afm_character **chars;
83     size_t char_cnt;
84   };
85
86 /* AFM file parser. */
87 struct parser 
88   {
89     struct pool *pool;          /* Containing pool. */
90     struct afm *afm;            /* AFM being parsed. */
91     FILE *file;                 /* File being parsed. */
92     const char *file_name;      /* Name of file being parsed. */
93     int line_number;            /* Current line number in file. */
94     jmp_buf bail_out;           /* longjmp() target for error handling. */
95
96     size_t char_allocated;
97     int max_code;
98   };
99
100 static struct afm *create_afm (void);
101 static struct afm_character *create_character (struct afm *);
102
103 static void afm_error (struct parser *, const char *, ...)
104      PRINTF_FORMAT (2, 3)
105      NO_RETURN;
106
107 static void parse_afm (struct parser *);
108 static void skip_section (struct parser *, const char *end_key);
109 static bool parse_set_specific (struct parser *, const char *end_key);
110 static void parse_direction (struct parser *);
111 static void parse_char_metrics (struct parser *);
112 static void parse_kern_pairs (struct parser *);
113 static void add_kern_pair (struct parser *p,
114                            struct afm_character *, struct afm_character *,
115                            int adjust);
116
117 static int skip_spaces (struct parser *);
118 static char *parse_key (struct parser *);
119 static void skip_line (struct parser *);
120 static void force_eol (struct parser *);
121 static bool get_integer (struct parser *, int *);
122 static int force_get_integer (struct parser *);
123 static bool get_number (struct parser *, int *);
124 static int force_get_number (struct parser *);
125 static bool get_hex_code (struct parser *, int *);
126 static int force_get_hex_code (struct parser *);
127 static bool get_word (struct parser *, char **);
128 static char *force_get_word (struct parser *);
129 static bool get_string (struct parser *, char **);
130 static char *force_get_string (struct parser *);
131
132 static struct afm_character *get_char_by_name (struct parser *, const char *);
133 static struct afm_character *get_char_by_code (const struct afm *, int code);
134
135 /* Reads FILE_NAME as an AFM file and returns the metrics data.
136    Returns a null pointer if the file cannot be parsed. */
137 struct afm *
138 afm_open (const char *file_name) 
139 {
140   struct afm *volatile afm;
141   struct parser *parser;
142
143   parser = pool_create_container (struct parser, pool);
144   afm = parser->afm = create_afm ();
145   parser->file = pool_fopen (parser->pool, file_name, "r");
146   parser->file_name = file_name;
147   parser->line_number = 0;
148   if (parser->file == NULL) 
149     {
150       error (0, errno, _("opening font metrics file \"%s\""), file_name);
151       goto error; 
152     }
153
154   if (setjmp (parser->bail_out))
155     goto error;
156
157   parse_afm (parser);
158   pool_destroy (parser->pool);
159   return afm;
160
161  error:
162   pool_destroy (parser->pool);
163   pool_destroy (afm->pool);
164   return create_afm ();
165 }
166
167 /* Creates and returns an empty set of metrics. */
168 static struct afm *
169 create_afm (void) 
170 {
171   struct afm *afm;
172   struct afm_character *def_char;
173   size_t i;
174
175   afm = pool_create_container (struct afm, pool);
176   afm->findfont_name = NULL;
177   afm->ascent = 0;
178   afm->descent = 0;
179   afm->mapping = MAP_UNKNOWN;
180   afm->escape_char = 255;
181   afm->shift_out = 14;
182   afm->shift_in = 15;
183   def_char = create_character (afm);
184   for (i = 0; i < 256; i++) 
185     afm->undefined_codes[i] = def_char;
186   for (i = 0; i < 256; i++) 
187     afm->codes[i] = afm->undefined_codes; 
188   afm->chars = NULL;
189   afm->char_cnt = 0;
190
191   return afm;
192 }
193
194 /* Creates and returns an initialized character within AFM. */
195 static struct afm_character *
196 create_character (struct afm *afm) 
197 {
198   struct afm_character *c = pool_alloc (afm->pool, sizeof *c);
199   c->code = ' ';
200   c->name = NULL;
201   c->width = 12000;
202   c->ascent = 0;
203   c->descent = 0;
204   c->kern_pairs = NULL;
205   c->kern_pair_cnt = 0;
206   c->ligatures = NULL;
207   c->ligature_cnt = 0;
208   return c;
209 }
210
211 /* Reports the given MESSAGE at the current line in parser P
212    and bails out with longjmp(). */
213 static void
214 afm_error (struct parser *p, const char *message, ...) 
215 {
216   va_list args;
217   char *msg;
218
219   va_start (args, message);
220   msg = xasprintf (message, args);
221   va_end (args);
222
223   error_at_line (0, 0, p->file_name, p->line_number, "%s", msg);
224   free (msg);
225
226   longjmp (p->bail_out, 1);
227 }
228
229 /* Parses an AFM file with parser P. */
230 static void
231 parse_afm (struct parser *p) 
232 {
233   char *key;
234
235   p->char_allocated = 0;
236   p->max_code = 0;
237
238   key = force_get_word (p);
239   if (strcmp (key, "StartFontMetrics"))
240     afm_error (p, _("first line must be StartFontMetrics"));
241   skip_line (p);
242
243   do
244     {
245       key = parse_key (p);
246       if (!strcmp (key, "FontName")) 
247         p->afm->findfont_name = pool_strdup (p->afm->pool,
248                                              force_get_string (p));
249       else if (!strcmp (key, "Ascender"))
250         p->afm->ascent = force_get_integer (p);
251       else if (!strcmp (key, "Descender"))
252         p->afm->descent = force_get_integer (p);
253       else if (!strcmp (key, "MappingScheme")) 
254         {
255           int scheme = force_get_integer (p);
256           if (scheme == 4)
257             p->afm->mapping = MAP_ONE_BYTE;
258           else if (scheme == 2 || scheme == 5 || scheme == 6)
259             p->afm->mapping = MAP_TWO_BYTE;
260           else if (scheme == 3)
261             p->afm->mapping = MAP_ESCAPE;
262           else if (scheme == 7)
263             p->afm->mapping = MAP_DOUBLE_ESCAPE;
264           else if (scheme == 8)
265             p->afm->mapping = MAP_SHIFT;
266           else
267             afm_error (p, _("unsupported MappingScheme %d"), scheme);
268         }
269       else if (!strcmp (key, "EscChar"))
270         p->afm->escape_char = force_get_integer (p);
271       else if (!strcmp (key, "StartDirection"))
272         parse_direction (p);
273       else if (!strcmp (key, "StartCharMetrics"))
274         parse_char_metrics (p);
275       else if (!strcmp (key, "StartKernPairs")
276                || !strcmp (key, "StartKernPairs0"))
277         parse_kern_pairs (p);
278       else if (!strcmp (key, "StartTrackKern")) 
279         skip_section (p, "EndTrackKern");
280       else if (!strcmp (key, "StartComposites")) 
281         skip_section (p, "EndComposites");
282       else 
283         skip_line (p);
284     }
285   while (strcmp (key, "EndFontMetrics"));
286
287   if (p->afm->findfont_name == NULL)
288     afm_error (p, _("required FontName is missing"));
289   if (p->afm->mapping == MAP_UNKNOWN) 
290     {
291       /* There seem to be a number of fonts out there that use a
292          2-byte encoding but don't announce it with
293          MappingScheme. */
294       p->afm->mapping = p->max_code > 255 ? MAP_TWO_BYTE : MAP_ONE_BYTE;
295     }
296 }
297
298 /* Reads lines from parser P until one starts with END_KEY. */
299 static void
300 skip_section (struct parser *p, const char *end_key)
301 {
302   const char *key;
303   skip_line (p);
304   do 
305     {
306       key = parse_key (p);
307       skip_line (p);
308     }
309   while (strcmp (key, end_key));
310 }
311
312 /* Attempts to read an integer from parser P.
313    If one is found, and it is nonzero, skips lines until END_KEY
314    is encountered and returns false.
315    Otherwise, skips the rest of the line and returns true.
316    (This is useful because AFM files can have multiple sets of
317    metrics.  Set 0 is for normal text, other sets are for
318    vertical text, etc.  We only care about set 0.) */
319 static bool
320 parse_set_specific (struct parser *p, const char *end_key) 
321 {
322   int set;
323   
324   if (get_integer (p, &set) && set != 0) 
325     {
326       skip_section (p, end_key);
327       return false; 
328     }
329   else 
330     {
331       force_eol (p);
332       return true;
333     }
334 }
335
336 /* Parses a StartDirection...EndDirection section in parser P. */
337 static void
338 parse_direction (struct parser *p) 
339 {
340   const char *key;
341
342   if (!parse_set_specific (p, "EndDirection"))
343     return;
344
345   do 
346     {
347       key = parse_key (p);
348       if (!strcmp (key, "CharWidth")) 
349         p->afm->codes[0][0]->width = force_get_integer (p);
350       skip_line (p);
351     }
352   while (strcmp (key, "EndDirection"));
353 }
354
355 /* Parses a StartCharMetrics...EndCharMetrics section in parser
356    P. */
357 static void
358 parse_char_metrics (struct parser *p) 
359 {
360   struct parsing_ligature 
361     {
362       struct afm_character *first;
363       char *successor;
364       char *ligature;
365     };
366
367   struct parsing_ligature *ligatures = NULL;
368   size_t ligature_cnt = 0;
369   size_t ligature_allocated = 0;
370
371   size_t i;
372
373   skip_line (p);
374   
375   for (;;)
376     {
377       char *key;
378       struct afm_character *c;
379
380       key = parse_key (p);
381       if (!strcmp (key, "EndCharMetrics"))
382         break;
383       
384       if (p->afm->char_cnt == p->char_allocated)
385         p->afm->chars = pool_2nrealloc (p->afm->pool, p->afm->chars,
386                                         &p->char_allocated,
387                                         sizeof *p->afm->chars);
388       c = create_character (p->afm);
389
390       if (!strcmp (key, "C")) 
391         c->code = force_get_integer (p);
392       else if (!strcmp (key, "CH"))
393         c->code = force_get_hex_code (p);
394       else
395         afm_error (p, _("CharMetrics line must start with C or CH"));
396       if (c->code < 0 || c->code > 65535)
397         c->code = -1;
398
399       if (c->code > p->max_code)
400         p->max_code = c->code;        
401
402       p->afm->chars[p->afm->char_cnt++] = c;
403       if (c->code != -1)
404         p->afm->codes[c->code >> 8][c->code & 0xff] = c;
405
406       key = force_get_word (p);
407       while (!strcmp (key, ";")) 
408         {
409           if (!get_word (p, &key))
410             break;
411
412           if (!strcmp (key, "N"))
413             c->name = force_get_word (p);
414           else if (!strcmp (key, "WX") || !strcmp (key, "W0X"))
415             c->width = force_get_number (p);
416           else if (!strcmp (key, "W") || !strcmp (key, "W0")) 
417             {
418               c->width = force_get_number (p);
419               force_get_number (p);
420             }
421           else if (!strcmp (key, "B")) 
422             {
423               int llx, lly, urx, ury;
424               llx = force_get_number (p);
425               lly = force_get_number (p);
426               urx = force_get_number (p);
427               ury = force_get_number (p);
428               c->ascent = MAX (0, ury);
429               c->descent = MAX (0, -lly);
430             }
431           else if (!strcmp (key, "L")) 
432             {
433               struct parsing_ligature *ligature;
434               if (ligature_cnt == ligature_allocated)
435                 ligatures = pool_2nrealloc (p->pool, ligatures,
436                                             &ligature_allocated,
437                                             sizeof *ligatures);
438               ligature = &ligatures[ligature_cnt++];
439               ligature->first = c;
440               ligature->successor = force_get_word (p);
441               ligature->ligature = force_get_word (p);
442             }
443           else 
444             {
445               while (strcmp (key, ";"))
446                 key = force_get_word (p);
447               continue;
448             }
449           if (!get_word (p, &key))
450             break;
451         }
452     }
453   skip_line (p);
454
455   for (i = 0; i < ligature_cnt; i++) 
456     {
457       struct parsing_ligature *src = &ligatures[i];
458       struct afm_ligature *dst;
459       src->first->ligatures = pool_nrealloc (p->afm->pool,
460                                              src->first->ligatures,
461                                              src->first->ligature_cnt + 1,
462                                              sizeof *src->first->ligatures);
463       dst = &src->first->ligatures[src->first->ligature_cnt++];
464       dst->successor = get_char_by_name (p, src->successor);
465       dst->ligature = get_char_by_name (p, src->ligature);
466     }
467 }
468
469 /* Parses a StartKernPairs...EndKernPairs section in parser P. */
470 static void
471 parse_kern_pairs (struct parser *p) 
472 {
473   char *key;
474   
475   skip_line (p);
476
477   do
478     {
479       struct afm_character *c1, *c2;
480       int adjust;
481
482       key = parse_key (p);
483       if (!strcmp (key, "KP") || !strcmp (key, "KPX")) 
484         {
485           c1 = get_char_by_name (p, force_get_word (p));
486           c2 = get_char_by_name (p, force_get_word (p));
487           adjust = force_get_number (p);
488           if (!strcmp (key, "KP"))
489             force_get_number (p);
490           add_kern_pair (p, c1, c2, adjust);
491         }
492       else if (!strcmp (key, "KPH")) 
493         {
494           c1 = get_char_by_code (p->afm, force_get_hex_code (p));
495           c2 = get_char_by_code (p->afm, force_get_hex_code (p));
496           adjust = force_get_number (p);
497           force_get_number (p);
498           add_kern_pair (p, c1, c2, adjust);
499         }
500       else
501         skip_line (p);
502     }
503   while (strcmp (key, "EndKernPairs"));
504 }
505
506 /* Adds a kern pair that adjusts (FIRST, SECOND) by ADJUST units
507    to the metrics within parser P. */
508 static void
509 add_kern_pair (struct parser *p, struct afm_character *first,
510                struct afm_character *second, int adjust) 
511 {
512   struct afm_kern_pair *kp;
513   
514   first->kern_pairs = pool_nrealloc (p->afm->pool, first->kern_pairs,
515                                      first->kern_pair_cnt + 1,
516                                      sizeof *first->kern_pairs);
517   kp = &first->kern_pairs[first->kern_pair_cnt++];
518   kp->successor = second;
519   kp->adjust = adjust;
520 }
521
522 /* Returns the character with the given NAME with the metrics for
523    parser P.  Reports an error if no character has the given
524    name. */
525 static struct afm_character *
526 get_char_by_name (struct parser *p, const char *name) 
527 {
528   size_t i;
529
530   for (i = 0; i < p->afm->char_cnt; i++) 
531     {
532       struct afm_character *c = p->afm->chars[i];
533       if (c->name != NULL && !strcmp (c->name, name))
534         return c;
535     }
536   afm_error (p, _("reference to unknown character \"%s\""), name);
537 }
538
539 /* Returns the character with the given CODE within AFM.
540    Returns a default character if the font doesn't have a
541    character with that code. */
542 static struct afm_character *
543 get_char_by_code (const struct afm *afm, int code_) 
544 {
545   uint16_t code = code_;
546   return afm->codes[code >> 8][code & 0xff];
547 }
548 \f
549 /* Skips white space, except for new-lines, within parser P. */
550 static int
551 skip_spaces (struct parser *p) 
552 {
553   int c;
554   while (isspace (c = getc (p->file)) && c != '\n')
555     continue;
556   ungetc (c, p->file);
557   return c;
558 }
559
560 /* Parses a word at the beginning of a line.
561    Skips comments.
562    Reports an error if not at the beginning of a line. */
563 static char *
564 parse_key (struct parser *p) 
565 {
566   force_eol (p);
567   for (;;) 
568     {
569       char *key;
570
571       do 
572         {
573           p->line_number++;
574           getc (p->file); 
575         }
576       while (skip_spaces (p) == '\n');
577
578       key = force_get_word (p);
579       if (strcmp (key, "Comment")) 
580         return key;
581
582       skip_line (p);
583     }
584 }
585
586 /* Skips to the next line within parser P. */
587 static void
588 skip_line (struct parser *p) 
589 {
590   for (;;) 
591     {
592       int c = getc (p->file);
593       if (c == EOF)
594         afm_error (p, _("expected end of file"));
595       if (c == '\n')
596         break;
597     }
598   ungetc ('\n', p->file);
599 }
600
601 /* Ensures that parser P is at the end of a line. */
602 static void
603 force_eol (struct parser *p) 
604 {
605   if (skip_spaces (p) != '\n')
606     afm_error (p, _("syntax error expecting end of line"));
607 }
608   
609 /* Tries to read an integer into *INTEGER at the current position
610    in parser P.
611    Returns success. */
612 static bool
613 get_integer (struct parser *p, int *integer) 
614 {
615   int c = skip_spaces (p);
616   if (isdigit (c) || c == '-') 
617     {
618       char *tail;
619       long tmp;
620
621       errno = 0;
622       tmp = strtol (force_get_word (p), &tail, 10);
623       if (errno == ERANGE || tmp < INT_MIN || tmp > INT_MAX) 
624         afm_error (p, _("number out of valid range"));
625       if (*tail != '\0')
626         afm_error (p, _("invalid numeric syntax"));
627       *integer = tmp;
628
629       return true;
630     }
631   else
632     return false;
633 }
634
635 /* Returns an integer read from the current position in P.
636    Reports an error if unsuccessful. */
637 static int
638 force_get_integer (struct parser *p) 
639 {
640   int integer;
641   if (!get_integer (p, &integer))
642     afm_error (p, _("syntax error expecting integer"));
643   return integer;
644 }
645
646 /* Tries to read a floating-point number at the current position
647    in parser P.  Stores the number's integer part into *INTEGER.
648    Returns success. */
649 static bool
650 get_number (struct parser *p, int *integer) 
651 {
652   int c = skip_spaces (p);
653   if (c == '-' || c == '.' || isdigit (c))
654     {
655       char *tail;
656       double number;
657
658       errno = 0;
659       number = c_strtod (force_get_word (p), &tail);
660       if (errno == ERANGE || number < INT_MIN || number > INT_MAX) 
661         afm_error (p, _("number out of valid range"));
662       if (*tail != '\0')
663         afm_error (p, _("invalid numeric syntax"));
664       *integer = number;
665
666       return true;
667     }
668   else
669     return false;
670 }
671
672 /* Returns the integer part of a floating-point number read from
673    the current position in P.
674    Reports an error if unsuccessful. */
675 static int
676 force_get_number (struct parser *p) 
677 {
678   int integer;
679   if (!get_number (p, &integer))
680     afm_error (p, _("syntax error expecting number"));
681   return integer;
682 }
683
684 /* Tries to read an integer expressed in hexadecimal into
685    *INTEGER from P.
686    Returns success. */
687 static bool
688 get_hex_code (struct parser *p, int *integer) 
689 {
690   if (skip_spaces (p) == '<') 
691     {
692       if (fscanf (p->file, "<%x", integer) != 1 || getc (p->file) != '>')
693         afm_error (p, _("syntax error in hex constant"));
694       return true;
695     }
696   else
697     return false;
698 }
699
700 /* Reads an integer expressed in hexadecimal and returns its
701    value.
702    Reports an error if unsuccessful. */
703 static int
704 force_get_hex_code (struct parser *p)
705 {
706   int integer;
707   if (!get_hex_code (p, &integer))
708     afm_error (p, _("syntax error expecting hex constant"));
709   return integer;
710 }
711
712 /* Tries to read a word from P into *WORD.
713    The word is allocated in P's pool.
714    Returns success. */
715 static bool
716 get_word (struct parser *p, char **word) 
717 {
718   if (skip_spaces (p) != '\n') 
719     {
720       struct string s;
721       int c;
722
723       ds_init (&s, 0);
724       while (!isspace (c = getc (p->file)) && c != EOF)
725         ds_putc (&s, c);
726       ungetc (c, p->file);
727       *word = ds_c_str (&s);
728       pool_register (p->pool, free, *word);
729       return true;
730     }
731   else 
732     {
733       *word = NULL;
734       return false;
735     }
736 }
737
738 /* Reads a word from P and returns it.
739    The word is allocated in P's pool.
740    Reports an error if unsuccessful. */
741 static char *
742 force_get_word (struct parser *p) 
743 {
744   char *word;
745   if (!get_word (p, &word))
746     afm_error (p, _("unexpected end of line"));
747   return word;
748 }
749
750 /* Reads a string, consisting of the remainder of the current
751    line, from P, and stores it in *STRING.
752    Leading and trailing spaces are removed.
753    The word is allocated in P's pool.
754    Returns true if a non-empty string was successfully read,
755    false otherwise. */
756 static bool
757 get_string (struct parser *p, char **string)
758 {
759   struct string s;
760
761   ds_init (&s, 0);
762   skip_spaces (p);
763   for (;;) 
764     {
765       int c = getc (p->file);
766       if (c == EOF || c == '\n')
767         break;
768       ds_putc (&s, c);
769     }
770   ungetc ('\n', p->file);
771   ds_rtrim_spaces (&s);
772
773   if (!ds_is_empty (&s)) 
774     {
775       *string = ds_c_str (&s);
776       pool_register (p->pool, free, *string);
777       return true;
778     }
779   else 
780     {
781       *string = NULL;
782       ds_destroy (&s);
783       return false;
784     }
785 }
786
787 /* Reads a string, consisting of the remainder of the current
788    line, from P, and returns it.
789    Leading and trailing spaces are removed.
790    The word is allocated in P's pool.
791    Reports an error if the string is empty. */
792 static char *
793 force_get_string (struct parser *p) 
794 {
795   char *string;
796   if (!get_string (p, &string))
797     afm_error (p, _("unexpected end of line expecting string"));
798   return string;
799 }
800 \f
801 /* Closes AFM and frees its storage. */
802 void
803 afm_close (struct afm *afm) 
804 {
805   if (afm != NULL)
806     pool_destroy (afm->pool);
807 }
808
809 /* Returns the string that must be passed to the PostScript
810    "findfont" operator to obtain AFM's font. */
811 const char *
812 afm_get_findfont_name (const struct afm *afm) 
813 {
814   return afm->findfont_name;
815 }
816
817 /* Returns the ascent for AFM, that is, the font's height above
818    the baseline, in units of 1/1000 of the nominal font size. */
819 int
820 afm_get_ascent (const struct afm *afm) 
821 {
822   return afm->ascent;
823 }
824
825 /* Returns the descent for AFM, that is, the font's depth below
826    the baseline, in units of 1/1000 of the nominal font size. */
827 int
828 afm_get_descent (const struct afm *afm) 
829 {
830   return afm->descent;
831 }
832
833 /* Returns the character numbered CODE within AFM,
834    or a default character if the font has none. */
835 const struct afm_character *
836 afm_get_character (const struct afm *afm, int code) 
837 {
838   return get_char_by_code (afm, code);
839 }
840
841 /* Returns the ligature formed when FIRST is followed by SECOND,
842    or a null pointer if there is no such ligature. */
843 const struct afm_character *
844 afm_get_ligature (const struct afm_character *first,
845                   const struct afm_character *second) 
846 {
847   size_t i;
848
849   for (i = 0; i < first->ligature_cnt; i++)
850     if (first->ligatures[i].successor == second)
851       return first->ligatures[i].ligature;
852   return NULL;
853 }
854
855 /* Returns the pair kerning x-adjustment when FIRST is followed
856    by SECOND, or 0 if no pair kerning should be done for the
857    given pair of characters. */
858 int
859 afm_get_kern_adjustment (const struct afm_character *first,
860                          const struct afm_character *second)
861 {
862   size_t i;
863
864   for (i = 0; i < first->kern_pair_cnt; i++)
865     if (first->kern_pairs[i].successor == second)
866       return first->kern_pairs[i].adjust;
867   return 0;
868 }
869 \f
870 /* Encodes the N characters in S as a PostScript string in OUT,
871    using a single-byte encoding.
872    Returns the number of characters remaining after all those
873    that could be successfully encoded were. */
874 static size_t
875 encode_one_byte (const struct afm_character **s, size_t n,
876                  struct string *out)
877 {
878   ds_putc (out, '(');
879   for (; n > 0; s++, n--)
880     {
881       uint8_t code = (*s)->code;
882       if (code != (*s)->code)
883         break;
884           
885       if (code == '(' || code == ')' || code == '\\')
886         ds_printf (out, "\\%c", code);
887       else if (!c_isprint (code))
888         ds_printf (out, "\\%03o", code);
889       else
890         ds_putc (out, code); 
891     }
892   ds_putc (out, ')');
893   return n;
894 }
895
896 /* State of binary encoder for PostScript. */
897 struct binary_encoder
898   {
899     struct string *out;         /* Output string. */
900     uint32_t b;                 /* Accumulated bytes for base-85 encoding. */
901     size_t n;                   /* Number of bytes in b (0...3). */
902   };
903
904 /* Initializes encoder E for output to OUT. */
905 static void
906 binary_init (struct binary_encoder *e, struct string *out) 
907 {
908   e->out = out;
909   e->b = e->n = 0;
910 }
911
912 /* Returns the character that represents VALUE in ASCII85
913    encoding. */
914 static int
915 value_to_ascii85 (int value) 
916 {
917   assert (value >= 0 && value < 85);
918 #if C_CTYPE_ASCII
919   return value + 33;
920 #else
921   return ("!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJK"
922           "LMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu")[value];
923 #endif
924 }
925
926 /* Appends the first N characters of the ASCII85 representation
927    of B to string OUT. */
928 static void
929 append_ascii85_block (unsigned b, size_t n, struct string *out) 
930 {
931   char c[5];
932   int i;
933
934   for (i = 4; i >= 0; i--) 
935     {
936       c[i] = value_to_ascii85 (b % 85);
937       b /= 85; 
938     }
939   ds_concat (out, c, n);
940 }
941
942 /* Encodes BYTE with encoder E. */
943 static void
944 binary_put (struct binary_encoder *e, uint8_t byte) 
945 {
946   e->b = (e->b << 8) | byte;
947   e->n++;
948   if (e->n % 4 == 0)
949     {
950       if (e->n == 4)
951         ds_puts (e->out, "<~");
952
953       if (e->b != 0)
954         append_ascii85_block (e->b, 5, e->out);
955       else 
956         ds_putc (e->out, 'z');
957     }
958 }
959
960 /* Finishes up encoding with E. */
961 static void
962 binary_finish (struct binary_encoder *e) 
963 {
964   if (e->n >= 4) 
965     {
966       /* We output at least one complete ASCII85 block.
967          Finish up. */
968       size_t n = e->n % 4;
969       if (n > 0)
970         append_ascii85_block (e->b << 8 * (4 - n), n + 1, e->out); 
971       ds_puts (e->out, "~>");
972     }
973   else if (e->n > 0)
974     {
975       /* It's cheaper (or at least the same cost) to encode this
976          string in hexadecimal. */
977       uint32_t b;
978       size_t i;
979
980       ds_puts (e->out, "<");
981       b = e->b << 8 * (4 - e->n);
982       for (i = 0; i < e->n; i++) 
983         {
984           ds_printf (e->out, "%02x", b >> 24);
985           b <<= 8;
986         }
987       ds_puts (e->out, ">");
988     }
989   else 
990     {
991       /* Empty string. */
992       ds_puts (e->out, "()"); 
993     }
994 }
995
996 /* Encodes the N characters in S into encoder E,
997    using a two-byte encoding.
998    Returns the number of characters remaining after all those
999    that could be successfully encoded were. */
1000 static size_t
1001 encode_two_byte (const struct afm_character **s, size_t n,
1002                  struct binary_encoder *e)
1003 {
1004   for (; n > 0; s++, n--) 
1005     {
1006       uint16_t code = (*s)->code;
1007       if (code != (*s)->code)
1008         break;
1009
1010       binary_put (e, code >> 8);
1011       binary_put (e, code);
1012     }
1013   return n;
1014 }
1015
1016 /* Encodes the N characters in S into encoder E,
1017    using an escape-based encoding with ESCAPE_CHAR as escape.
1018    Returns the number of characters remaining after all those
1019    that could be successfully encoded were. */
1020 static size_t
1021 encode_escape (const struct afm_character **s, size_t n,
1022                unsigned char escape_char,
1023                struct binary_encoder *e)
1024 {
1025   uint8_t cur_font = 0;
1026
1027   for (; n > 0; s++, n--)
1028     {
1029       uint16_t code = (*s)->code;
1030       uint8_t font_num = code >> 8;
1031       uint8_t char_num = code & 0xff;
1032       if (code != (*s)->code)
1033         break;
1034
1035       if (font_num != cur_font) 
1036         {
1037           if (font_num == escape_char)
1038             break;
1039           binary_put (e, escape_char);
1040           binary_put (e, font_num);
1041           cur_font = font_num;
1042         }
1043       binary_put (e, char_num);
1044     }
1045   return n;
1046 }
1047
1048 /* Encodes the N characters in S into encoder E,
1049    using an double escape-based encoding with ESCAPE_CHAR as
1050    escape.
1051    Returns the number of characters remaining after all those
1052    that could be successfully encoded were. */
1053 static size_t
1054 encode_double_escape (const struct afm_character **s, size_t n,
1055                       unsigned char escape_char,
1056                       struct binary_encoder *e)
1057 {
1058   unsigned cur_font = 0;
1059
1060   for (; n > 0; s++, n--)
1061     {
1062       unsigned font_num = (*s)->code >> 8;
1063       uint8_t char_num = (*s)->code & 0xff;
1064       if ((*s)->code & ~0x1ffff)
1065         break;
1066
1067       if (font_num != cur_font) 
1068         {
1069           if (font_num == (escape_char & 0xff))
1070             break;
1071           if (font_num >= 256)
1072             binary_put (e, escape_char);
1073           binary_put (e, escape_char);
1074           binary_put (e, font_num & 0xff);
1075           cur_font = font_num;
1076         }
1077       binary_put (e, char_num);
1078     }
1079   return n;
1080 }
1081
1082 /* Encodes the N characters in S into encoder E,
1083    using a shift-based encoding with SHIFT_IN and SHIFT_OUT as
1084    shift characters.
1085    Returns the number of characters remaining after all those
1086    that could be successfully encoded were. */
1087 static size_t
1088 encode_shift (const struct afm_character **s, size_t n,
1089               unsigned char shift_in, unsigned char shift_out,
1090               struct binary_encoder *e)
1091 {
1092   unsigned cur_font = 0;
1093
1094   for (; n > 0; s++, n--)
1095     {
1096       int font_num = ((*s)->code & 0x100) != 0;
1097       uint8_t char_num = (*s)->code & 0xff;
1098       if ((*s)->code & ~0x1ff)
1099         break;
1100
1101       if (font_num != cur_font) 
1102         {
1103           binary_put (e, font_num ? shift_out : shift_in);
1104           cur_font = font_num;
1105         }
1106       binary_put (e, char_num);
1107     }
1108   return n;
1109 }
1110
1111 /* Encodes the N characters in S into a PostScript string in OUT,
1112    according to AFM's character encoding.
1113    Returns the number of characters successfully encoded,
1114    which may be less than N if an unencodable character was
1115    encountered. */
1116 size_t
1117 afm_encode_string (const struct afm *afm,
1118                    const struct afm_character **s, size_t n,
1119                    struct string *out) 
1120 {
1121   size_t initial_length = ds_length (out);
1122   size_t chars_left;
1123
1124   if (afm->mapping == MAP_ONE_BYTE)
1125     chars_left = encode_one_byte (s, n, out);
1126   else 
1127     {
1128       struct binary_encoder e;
1129
1130       binary_init (&e, out);
1131       switch (afm->mapping) 
1132         {
1133         case MAP_TWO_BYTE:
1134           chars_left = encode_two_byte (s, n, &e);
1135           break;
1136
1137         case MAP_ESCAPE:
1138           chars_left = encode_escape (s, n, afm->escape_char, &e);
1139           break;
1140       
1141         case MAP_DOUBLE_ESCAPE:
1142           chars_left = encode_double_escape (s, n, afm->escape_char, &e);
1143           break;
1144
1145         case MAP_SHIFT:
1146           chars_left = encode_shift (s, n, afm->shift_in, afm->shift_out, &e);
1147           break;
1148       
1149         default:
1150           abort ();
1151         }
1152       binary_finish (&e);
1153     }
1154
1155   if (chars_left == n)
1156     ds_truncate (out, initial_length);
1157   return n - chars_left;
1158 }