0d6b30aeeb15ab1a06425b7776fa77b4ebb8d695
[pspp-builds.git] / src / output / afm.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 2006 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or
5    modify it under the terms of the GNU General Public License as
6    published by the Free Software Foundation; either version 2 of the
7    License, or (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17    02110-1301, USA. */
18
19 #include <config.h>
20 #include "afm.h"
21 #include "c-ctype.h"
22 #include "c-strtod.h"
23 #include <ctype.h>
24 #include <errno.h>
25 #include <limits.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/assertion.h>
35 #include <libpspp/pool.h>
36 #include <libpspp/str.h>
37
38 #include "gettext.h"
39 #define _(msgid) gettext (msgid)
40
41 /* A kern pair entry. */
42 struct afm_kern_pair
43   {
44     struct afm_character *successor; /* Second character. */
45     int adjust;                 /* Adjustment. */
46   };
47
48 /* A ligature. */
49 struct afm_ligature
50   {
51     struct afm_character *successor; /* Second character. */
52     struct afm_character *ligature;  /* Resulting ligature. */
53   };
54
55 /* How to map between byte strings and character values. */
56 enum mapping_scheme
57   {
58     MAP_UNKNOWN,                /* Not yet determined. */
59     MAP_ONE_BYTE,               /* 8-bit coding. */
60     MAP_TWO_BYTE,               /* 16-bit coding. */
61     MAP_ESCAPE,                 /* 8-bit coding with escape to change fonts. */
62     MAP_DOUBLE_ESCAPE,          /* 8-bit coding with multiple escapes. */
63     MAP_SHIFT                   /* 8-bit coding with 2 fonts that toggle. */
64   };
65
66 /* AFM file data.  */
67 struct afm
68   {
69     struct pool *pool;          /* Containing pool. */
70     char *findfont_name;        /* Name for PostScript /findfont operator. */
71     int ascent;                 /* Height above the baseline (non-negative). */
72     int descent;                /* Depth below the baseline (non-negative). */
73
74     /* Encoding characters into strings. */
75     enum mapping_scheme mapping; /* Basic mapping scheme. */
76     char escape_char;           /* MAP_ESCAPE only: escape character to use. */
77     char shift_out;             /* MAP_SHIFT only: selects font 0. */
78     char shift_in;              /* MAP_SHIFT only: selects font 1. */
79
80     /* Characters. */
81     struct afm_character *undefined_codes[256];
82     struct afm_character **codes[256];
83     struct afm_character **chars;
84     size_t char_cnt;
85   };
86
87 /* AFM file parser. */
88 struct parser
89   {
90     struct pool *pool;          /* Containing pool. */
91     struct afm *afm;            /* AFM being parsed. */
92     FILE *file;                 /* File being parsed. */
93     const char *file_name;      /* Name of file being parsed. */
94     int line_number;            /* Current line number in file. */
95     jmp_buf bail_out;           /* longjmp() target for error handling. */
96
97     size_t char_allocated;
98     int max_code;
99   };
100
101 static struct afm *create_afm (void);
102 static struct afm_character *create_character (struct afm *);
103
104 static void afm_error (struct parser *, const char *, ...)
105      PRINTF_FORMAT (2, 3)
106      NO_RETURN;
107
108 static void parse_afm (struct parser *);
109 static void skip_section (struct parser *, const char *end_key);
110 static bool parse_set_specific (struct parser *, const char *end_key);
111 static void parse_direction (struct parser *);
112 static void parse_char_metrics (struct parser *);
113 static void parse_kern_pairs (struct parser *);
114 static void add_kern_pair (struct parser *p,
115                            struct afm_character *, struct afm_character *,
116                            int adjust);
117
118 static int skip_spaces (struct parser *);
119 static char *parse_key (struct parser *);
120 static void skip_line (struct parser *);
121 static void force_eol (struct parser *);
122 static bool get_integer (struct parser *, int *);
123 static int force_get_integer (struct parser *);
124 static bool get_number (struct parser *, int *);
125 static int force_get_number (struct parser *);
126 static bool get_hex_code (struct parser *, int *);
127 static int force_get_hex_code (struct parser *);
128 static bool get_word (struct parser *, char **);
129 static char *force_get_word (struct parser *);
130 static bool get_string (struct parser *, char **);
131 static char *force_get_string (struct parser *);
132
133 static struct afm_character *get_char_by_name (struct parser *, const char *);
134 static struct afm_character *get_char_by_code (const struct afm *, int code);
135
136 /* Reads FILE_NAME as an AFM file and returns the metrics data.
137    Returns a null pointer if the file cannot be parsed. */
138 struct afm *
139 afm_open (const char *file_name)
140 {
141   struct afm *volatile afm;
142   struct parser *parser;
143
144   parser = pool_create_container (struct parser, pool);
145   afm = parser->afm = create_afm ();
146   parser->file = pool_fopen (parser->pool, file_name, "r");
147   parser->file_name = file_name;
148   parser->line_number = 0;
149   if (parser->file == NULL)
150     {
151       error (0, errno, _("opening font metrics file \"%s\""), file_name);
152       goto error;
153     }
154
155   if (setjmp (parser->bail_out))
156     goto error;
157
158   parse_afm (parser);
159   pool_destroy (parser->pool);
160   return afm;
161
162  error:
163   pool_destroy (parser->pool);
164   pool_destroy (afm->pool);
165   return create_afm ();
166 }
167
168 /* Creates and returns an empty set of metrics. */
169 static struct afm *
170 create_afm (void)
171 {
172   struct afm *afm;
173   struct afm_character *def_char;
174   size_t i;
175
176   afm = pool_create_container (struct afm, pool);
177   afm->findfont_name = NULL;
178   afm->ascent = 0;
179   afm->descent = 0;
180   afm->mapping = MAP_UNKNOWN;
181   afm->escape_char = 255;
182   afm->shift_out = 14;
183   afm->shift_in = 15;
184   def_char = create_character (afm);
185   for (i = 0; i < 256; i++)
186     afm->undefined_codes[i] = def_char;
187   for (i = 0; i < 256; i++)
188     afm->codes[i] = afm->undefined_codes;
189   afm->chars = NULL;
190   afm->char_cnt = 0;
191
192   return afm;
193 }
194
195 /* Creates and returns an initialized character within AFM. */
196 static struct afm_character *
197 create_character (struct afm *afm)
198 {
199   struct afm_character *c = pool_alloc (afm->pool, sizeof *c);
200   c->code = ' ';
201   c->name = NULL;
202   c->width = 12000;
203   c->ascent = 0;
204   c->descent = 0;
205   c->kern_pairs = NULL;
206   c->kern_pair_cnt = 0;
207   c->ligatures = NULL;
208   c->ligature_cnt = 0;
209   return c;
210 }
211
212 /* Reports the given MESSAGE at the current line in parser P
213    and bails out with longjmp(). */
214 static void
215 afm_error (struct parser *p, const char *message, ...)
216 {
217   va_list args;
218   char *msg;
219
220   va_start (args, message);
221   msg = xasprintf (message, args);
222   va_end (args);
223
224   error_at_line (0, 0, p->file_name, p->line_number, "%s", msg);
225   free (msg);
226
227   longjmp (p->bail_out, 1);
228 }
229
230 /* Parses an AFM file with parser P. */
231 static void
232 parse_afm (struct parser *p)
233 {
234   char *key;
235
236   p->char_allocated = 0;
237   p->max_code = 0;
238
239   key = force_get_word (p);
240   if (strcmp (key, "StartFontMetrics"))
241     afm_error (p, _("first line must be StartFontMetrics"));
242   skip_line (p);
243
244   do
245     {
246       key = parse_key (p);
247       if (!strcmp (key, "FontName"))
248         p->afm->findfont_name = pool_strdup (p->afm->pool,
249                                              force_get_string (p));
250       else if (!strcmp (key, "Ascender"))
251         p->afm->ascent = force_get_integer (p);
252       else if (!strcmp (key, "Descender"))
253         p->afm->descent = force_get_integer (p);
254       else if (!strcmp (key, "MappingScheme"))
255         {
256           int scheme = force_get_integer (p);
257           if (scheme == 4)
258             p->afm->mapping = MAP_ONE_BYTE;
259           else if (scheme == 2 || scheme == 5 || scheme == 6)
260             p->afm->mapping = MAP_TWO_BYTE;
261           else if (scheme == 3)
262             p->afm->mapping = MAP_ESCAPE;
263           else if (scheme == 7)
264             p->afm->mapping = MAP_DOUBLE_ESCAPE;
265           else if (scheme == 8)
266             p->afm->mapping = MAP_SHIFT;
267           else
268             afm_error (p, _("unsupported MappingScheme %d"), scheme);
269         }
270       else if (!strcmp (key, "EscChar"))
271         p->afm->escape_char = force_get_integer (p);
272       else if (!strcmp (key, "StartDirection"))
273         parse_direction (p);
274       else if (!strcmp (key, "StartCharMetrics"))
275         parse_char_metrics (p);
276       else if (!strcmp (key, "StartKernPairs")
277                || !strcmp (key, "StartKernPairs0"))
278         parse_kern_pairs (p);
279       else if (!strcmp (key, "StartTrackKern"))
280         skip_section (p, "EndTrackKern");
281       else if (!strcmp (key, "StartComposites"))
282         skip_section (p, "EndComposites");
283       else
284         skip_line (p);
285     }
286   while (strcmp (key, "EndFontMetrics"));
287
288   if (p->afm->findfont_name == NULL)
289     afm_error (p, _("required FontName is missing"));
290   if (p->afm->mapping == MAP_UNKNOWN)
291     {
292       /* There seem to be a number of fonts out there that use a
293          2-byte encoding but don't announce it with
294          MappingScheme. */
295       p->afm->mapping = p->max_code > 255 ? MAP_TWO_BYTE : MAP_ONE_BYTE;
296     }
297 }
298
299 /* Reads lines from parser P until one starts with END_KEY. */
300 static void
301 skip_section (struct parser *p, const char *end_key)
302 {
303   const char *key;
304   skip_line (p);
305   do
306     {
307       key = parse_key (p);
308       skip_line (p);
309     }
310   while (strcmp (key, end_key));
311 }
312
313 /* Attempts to read an integer from parser P.
314    If one is found, and it is nonzero, skips lines until END_KEY
315    is encountered and returns false.
316    Otherwise, skips the rest of the line and returns true.
317    (This is useful because AFM files can have multiple sets of
318    metrics.  Set 0 is for normal text, other sets are for
319    vertical text, etc.  We only care about set 0.) */
320 static bool
321 parse_set_specific (struct parser *p, const char *end_key)
322 {
323   int set;
324
325   if (get_integer (p, &set) && set != 0)
326     {
327       skip_section (p, end_key);
328       return false;
329     }
330   else
331     {
332       force_eol (p);
333       return true;
334     }
335 }
336
337 /* Parses a StartDirection...EndDirection section in parser P. */
338 static void
339 parse_direction (struct parser *p)
340 {
341   const char *key;
342
343   if (!parse_set_specific (p, "EndDirection"))
344     return;
345
346   do
347     {
348       key = parse_key (p);
349       if (!strcmp (key, "CharWidth"))
350         p->afm->codes[0][0]->width = force_get_integer (p);
351       skip_line (p);
352     }
353   while (strcmp (key, "EndDirection"));
354 }
355
356 /* Parses a StartCharMetrics...EndCharMetrics section in parser
357    P. */
358 static void
359 parse_char_metrics (struct parser *p)
360 {
361   struct parsing_ligature
362     {
363       struct afm_character *first;
364       char *successor;
365       char *ligature;
366     };
367
368   struct parsing_ligature *ligatures = NULL;
369   size_t ligature_cnt = 0;
370   size_t ligature_allocated = 0;
371
372   size_t i;
373
374   skip_line (p);
375
376   for (;;)
377     {
378       char *key;
379       struct afm_character *c;
380
381       key = parse_key (p);
382       if (!strcmp (key, "EndCharMetrics"))
383         break;
384
385       if (p->afm->char_cnt == p->char_allocated)
386         p->afm->chars = pool_2nrealloc (p->afm->pool, p->afm->chars,
387                                         &p->char_allocated,
388                                         sizeof *p->afm->chars);
389       c = create_character (p->afm);
390
391       if (!strcmp (key, "C"))
392         c->code = force_get_integer (p);
393       else if (!strcmp (key, "CH"))
394         c->code = force_get_hex_code (p);
395       else
396         afm_error (p, _("CharMetrics line must start with C or CH"));
397       if (c->code < 0 || c->code > 65535)
398         c->code = -1;
399
400       if (c->code > p->max_code)
401         p->max_code = c->code;
402
403       p->afm->chars[p->afm->char_cnt++] = c;
404       if (c->code != -1)
405         p->afm->codes[c->code >> 8][c->code & 0xff] = c;
406
407       key = force_get_word (p);
408       while (!strcmp (key, ";"))
409         {
410           if (!get_word (p, &key))
411             break;
412
413           if (!strcmp (key, "N"))
414             c->name = force_get_word (p);
415           else if (!strcmp (key, "WX") || !strcmp (key, "W0X"))
416             c->width = force_get_number (p);
417           else if (!strcmp (key, "W") || !strcmp (key, "W0"))
418             {
419               c->width = force_get_number (p);
420               force_get_number (p);
421             }
422           else if (!strcmp (key, "B"))
423             {
424               int llx, lly, urx, ury;
425               llx = force_get_number (p);
426               lly = force_get_number (p);
427               urx = force_get_number (p);
428               ury = force_get_number (p);
429               c->ascent = MAX (0, ury);
430               c->descent = MAX (0, -lly);
431             }
432           else if (!strcmp (key, "L"))
433             {
434               struct parsing_ligature *ligature;
435               if (ligature_cnt == ligature_allocated)
436                 ligatures = pool_2nrealloc (p->pool, ligatures,
437                                             &ligature_allocated,
438                                             sizeof *ligatures);
439               ligature = &ligatures[ligature_cnt++];
440               ligature->first = c;
441               ligature->successor = force_get_word (p);
442               ligature->ligature = force_get_word (p);
443             }
444           else
445             {
446               while (strcmp (key, ";"))
447                 key = force_get_word (p);
448               continue;
449             }
450           if (!get_word (p, &key))
451             break;
452         }
453     }
454   skip_line (p);
455
456   for (i = 0; i < ligature_cnt; i++)
457     {
458       struct parsing_ligature *src = &ligatures[i];
459       struct afm_ligature *dst;
460       src->first->ligatures = pool_nrealloc (p->afm->pool,
461                                              src->first->ligatures,
462                                              src->first->ligature_cnt + 1,
463                                              sizeof *src->first->ligatures);
464       dst = &src->first->ligatures[src->first->ligature_cnt++];
465       dst->successor = get_char_by_name (p, src->successor);
466       dst->ligature = get_char_by_name (p, src->ligature);
467     }
468 }
469
470 /* Parses a StartKernPairs...EndKernPairs section in parser P. */
471 static void
472 parse_kern_pairs (struct parser *p)
473 {
474   char *key;
475
476   skip_line (p);
477
478   do
479     {
480       struct afm_character *c1, *c2;
481       int adjust;
482
483       key = parse_key (p);
484       if (!strcmp (key, "KP") || !strcmp (key, "KPX"))
485         {
486           c1 = get_char_by_name (p, force_get_word (p));
487           c2 = get_char_by_name (p, force_get_word (p));
488           adjust = force_get_number (p);
489           if (!strcmp (key, "KP"))
490             force_get_number (p);
491           add_kern_pair (p, c1, c2, adjust);
492         }
493       else if (!strcmp (key, "KPH"))
494         {
495           c1 = get_char_by_code (p->afm, force_get_hex_code (p));
496           c2 = get_char_by_code (p->afm, force_get_hex_code (p));
497           adjust = force_get_number (p);
498           force_get_number (p);
499           add_kern_pair (p, c1, c2, adjust);
500         }
501       else
502         skip_line (p);
503     }
504   while (strcmp (key, "EndKernPairs"));
505 }
506
507 /* Adds a kern pair that adjusts (FIRST, SECOND) by ADJUST units
508    to the metrics within parser P. */
509 static void
510 add_kern_pair (struct parser *p, struct afm_character *first,
511                struct afm_character *second, int adjust)
512 {
513   struct afm_kern_pair *kp;
514
515   first->kern_pairs = pool_nrealloc (p->afm->pool, first->kern_pairs,
516                                      first->kern_pair_cnt + 1,
517                                      sizeof *first->kern_pairs);
518   kp = &first->kern_pairs[first->kern_pair_cnt++];
519   kp->successor = second;
520   kp->adjust = adjust;
521 }
522
523 /* Returns the character with the given NAME with the metrics for
524    parser P.  Reports an error if no character has the given
525    name. */
526 static struct afm_character *
527 get_char_by_name (struct parser *p, const char *name)
528 {
529   size_t i;
530
531   for (i = 0; i < p->afm->char_cnt; i++)
532     {
533       struct afm_character *c = p->afm->chars[i];
534       if (c->name != NULL && !strcmp (c->name, name))
535         return c;
536     }
537   afm_error (p, _("reference to unknown character \"%s\""), name);
538 }
539
540 /* Returns the character with the given CODE within AFM.
541    Returns a default character if the font doesn't have a
542    character with that code. */
543 static struct afm_character *
544 get_char_by_code (const struct afm *afm, int code_)
545 {
546   uint16_t code = code_;
547   return afm->codes[code >> 8][code & 0xff];
548 }
549 \f
550 /* Skips white space, except for new-lines, within parser P. */
551 static int
552 skip_spaces (struct parser *p)
553 {
554   int c;
555   while (isspace (c = getc (p->file)) && c != '\n')
556     continue;
557   ungetc (c, p->file);
558   return c;
559 }
560
561 /* Parses a word at the beginning of a line.
562    Skips comments.
563    Reports an error if not at the beginning of a line. */
564 static char *
565 parse_key (struct parser *p)
566 {
567   force_eol (p);
568   for (;;)
569     {
570       char *key;
571
572       do
573         {
574           p->line_number++;
575           getc (p->file);
576         }
577       while (skip_spaces (p) == '\n');
578
579       key = force_get_word (p);
580       if (strcmp (key, "Comment"))
581         return key;
582
583       skip_line (p);
584     }
585 }
586
587 /* Skips to the next line within parser P. */
588 static void
589 skip_line (struct parser *p)
590 {
591   for (;;)
592     {
593       int c = getc (p->file);
594       if (c == EOF)
595         afm_error (p, _("expected end of file"));
596       if (c == '\n')
597         break;
598     }
599   ungetc ('\n', p->file);
600 }
601
602 /* Ensures that parser P is at the end of a line. */
603 static void
604 force_eol (struct parser *p)
605 {
606   if (skip_spaces (p) != '\n')
607     afm_error (p, _("syntax error expecting end of line"));
608 }
609
610 /* Tries to read an integer into *INTEGER at the current position
611    in parser P.
612    Returns success. */
613 static bool
614 get_integer (struct parser *p, int *integer)
615 {
616   int c = skip_spaces (p);
617   if (isdigit (c) || c == '-')
618     {
619       char *tail;
620       long tmp;
621
622       errno = 0;
623       tmp = strtol (force_get_word (p), &tail, 10);
624       if (errno == ERANGE || tmp < INT_MIN || tmp > INT_MAX)
625         afm_error (p, _("number out of valid range"));
626       if (*tail != '\0')
627         afm_error (p, _("invalid numeric syntax"));
628       *integer = tmp;
629
630       return true;
631     }
632   else
633     return false;
634 }
635
636 /* Returns an integer read from the current position in P.
637    Reports an error if unsuccessful. */
638 static int
639 force_get_integer (struct parser *p)
640 {
641   int integer;
642   if (!get_integer (p, &integer))
643     afm_error (p, _("syntax error expecting integer"));
644   return integer;
645 }
646
647 /* Tries to read a floating-point number at the current position
648    in parser P.  Stores the number's integer part into *INTEGER.
649    Returns success. */
650 static bool
651 get_number (struct parser *p, int *integer)
652 {
653   int c = skip_spaces (p);
654   if (c == '-' || c == '.' || isdigit (c))
655     {
656       char *tail;
657       double number;
658
659       errno = 0;
660       number = c_strtod (force_get_word (p), &tail);
661       if (errno == ERANGE || number < INT_MIN || number > INT_MAX)
662         afm_error (p, _("number out of valid range"));
663       if (*tail != '\0')
664         afm_error (p, _("invalid numeric syntax"));
665       *integer = number;
666
667       return true;
668     }
669   else
670     return false;
671 }
672
673 /* Returns the integer part of a floating-point number read from
674    the current position in P.
675    Reports an error if unsuccessful. */
676 static int
677 force_get_number (struct parser *p)
678 {
679   int integer;
680   if (!get_number (p, &integer))
681     afm_error (p, _("syntax error expecting number"));
682   return integer;
683 }
684
685 /* Tries to read an integer expressed in hexadecimal into
686    *INTEGER from P.
687    Returns success. */
688 static bool
689 get_hex_code (struct parser *p, int *integer)
690 {
691   if (skip_spaces (p) == '<')
692     {
693       if (fscanf (p->file, "<%x", integer) != 1 || getc (p->file) != '>')
694         afm_error (p, _("syntax error in hex constant"));
695       return true;
696     }
697   else
698     return false;
699 }
700
701 /* Reads an integer expressed in hexadecimal and returns its
702    value.
703    Reports an error if unsuccessful. */
704 static int
705 force_get_hex_code (struct parser *p)
706 {
707   int integer;
708   if (!get_hex_code (p, &integer))
709     afm_error (p, _("syntax error expecting hex constant"));
710   return integer;
711 }
712
713 /* Tries to read a word from P into *WORD.
714    The word is allocated in P's pool.
715    Returns success. */
716 static bool
717 get_word (struct parser *p, char **word)
718 {
719   if (skip_spaces (p) != '\n')
720     {
721       struct string s;
722       int c;
723
724       ds_init_empty (&s);
725       while (!isspace (c = getc (p->file)) && c != EOF)
726         ds_put_char (&s, c);
727       ungetc (c, p->file);
728       *word = ds_cstr (&s);
729       pool_register (p->pool, free, *word);
730       return true;
731     }
732   else
733     {
734       *word = NULL;
735       return false;
736     }
737 }
738
739 /* Reads a word from P and returns it.
740    The word is allocated in P's pool.
741    Reports an error if unsuccessful. */
742 static char *
743 force_get_word (struct parser *p)
744 {
745   char *word;
746   if (!get_word (p, &word))
747     afm_error (p, _("unexpected end of line"));
748   return word;
749 }
750
751 /* Reads a string, consisting of the remainder of the current
752    line, from P, and stores it in *STRING.
753    Leading and trailing spaces are removed.
754    The word is allocated in P's pool.
755    Returns true if a non-empty string was successfully read,
756    false otherwise. */
757 static bool
758 get_string (struct parser *p, char **string)
759 {
760   struct string s = DS_EMPTY_INITIALIZER;
761
762   skip_spaces (p);
763   for (;;)
764     {
765       int c = getc (p->file);
766       if (c == EOF || c == '\n')
767         break;
768       ds_put_char (&s, c);
769     }
770   ungetc ('\n', p->file);
771   ds_rtrim (&s, ss_cstr (CC_SPACES));
772
773   if (!ds_is_empty (&s))
774     {
775       *string = ds_cstr (&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_put_char (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_put_format (out, "\\%c", code);
887       else if (!c_isprint (code))
888         ds_put_format (out, "\\%03o", code);
889       else
890         ds_put_char (out, code);
891     }
892   ds_put_char (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_put_substring (out, ss_buffer (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_put_cstr (e->out, "<~");
952
953       if (e->b != 0)
954         append_ascii85_block (e->b, 5, e->out);
955       else
956         ds_put_char (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_put_cstr (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_put_cstr (e->out, "<");
981       b = e->b << 8 * (4 - e->n);
982       for (i = 0; i < e->n; i++)
983         {
984           ds_put_format (e->out, "%02x", b >> 24);
985           b <<= 8;
986         }
987       ds_put_cstr (e->out, ">");
988     }
989   else
990     {
991       /* Empty string. */
992       ds_put_cstr (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           NOT_REACHED ();
1151         }
1152       binary_finish (&e);
1153     }
1154
1155   if (chars_left == n)
1156     ds_truncate (out, initial_length);
1157   return n - chars_left;
1158 }