af4f8199fe1e4c5f9469298a601c9a30f666d42b
[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 <stdarg.h>
26 #include <stdbool.h>
27 #include <stdint.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <setjmp.h>
31 #include "error.h"
32 #include "minmax.h"
33 #include <libpspp/assertion.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_empty (&s);
724       while (!isspace (c = getc (p->file)) && c != EOF)
725         ds_put_char (&s, c);
726       ungetc (c, p->file);
727       *word = ds_cstr (&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 = DS_EMPTY_INITIALIZER;
760
761   skip_spaces (p);
762   for (;;) 
763     {
764       int c = getc (p->file);
765       if (c == EOF || c == '\n')
766         break;
767       ds_put_char (&s, c);
768     }
769   ungetc ('\n', p->file);
770   ds_rtrim (&s, ss_cstr (CC_SPACES));
771
772   if (!ds_is_empty (&s)) 
773     {
774       *string = ds_cstr (&s);
775       pool_register (p->pool, free, *string);
776       return true;
777     }
778   else 
779     {
780       *string = NULL;
781       ds_destroy (&s);
782       return false;
783     }
784 }
785
786 /* Reads a string, consisting of the remainder of the current
787    line, from P, and returns it.
788    Leading and trailing spaces are removed.
789    The word is allocated in P's pool.
790    Reports an error if the string is empty. */
791 static char *
792 force_get_string (struct parser *p) 
793 {
794   char *string;
795   if (!get_string (p, &string))
796     afm_error (p, _("unexpected end of line expecting string"));
797   return string;
798 }
799 \f
800 /* Closes AFM and frees its storage. */
801 void
802 afm_close (struct afm *afm) 
803 {
804   if (afm != NULL)
805     pool_destroy (afm->pool);
806 }
807
808 /* Returns the string that must be passed to the PostScript
809    "findfont" operator to obtain AFM's font. */
810 const char *
811 afm_get_findfont_name (const struct afm *afm) 
812 {
813   return afm->findfont_name;
814 }
815
816 /* Returns the ascent for AFM, that is, the font's height above
817    the baseline, in units of 1/1000 of the nominal font size. */
818 int
819 afm_get_ascent (const struct afm *afm) 
820 {
821   return afm->ascent;
822 }
823
824 /* Returns the descent for AFM, that is, the font's depth below
825    the baseline, in units of 1/1000 of the nominal font size. */
826 int
827 afm_get_descent (const struct afm *afm) 
828 {
829   return afm->descent;
830 }
831
832 /* Returns the character numbered CODE within AFM,
833    or a default character if the font has none. */
834 const struct afm_character *
835 afm_get_character (const struct afm *afm, int code) 
836 {
837   return get_char_by_code (afm, code);
838 }
839
840 /* Returns the ligature formed when FIRST is followed by SECOND,
841    or a null pointer if there is no such ligature. */
842 const struct afm_character *
843 afm_get_ligature (const struct afm_character *first,
844                   const struct afm_character *second) 
845 {
846   size_t i;
847
848   for (i = 0; i < first->ligature_cnt; i++)
849     if (first->ligatures[i].successor == second)
850       return first->ligatures[i].ligature;
851   return NULL;
852 }
853
854 /* Returns the pair kerning x-adjustment when FIRST is followed
855    by SECOND, or 0 if no pair kerning should be done for the
856    given pair of characters. */
857 int
858 afm_get_kern_adjustment (const struct afm_character *first,
859                          const struct afm_character *second)
860 {
861   size_t i;
862
863   for (i = 0; i < first->kern_pair_cnt; i++)
864     if (first->kern_pairs[i].successor == second)
865       return first->kern_pairs[i].adjust;
866   return 0;
867 }
868 \f
869 /* Encodes the N characters in S as a PostScript string in OUT,
870    using a single-byte encoding.
871    Returns the number of characters remaining after all those
872    that could be successfully encoded were. */
873 static size_t
874 encode_one_byte (const struct afm_character **s, size_t n,
875                  struct string *out)
876 {
877   ds_put_char (out, '(');
878   for (; n > 0; s++, n--)
879     {
880       uint8_t code = (*s)->code;
881       if (code != (*s)->code)
882         break;
883           
884       if (code == '(' || code == ')' || code == '\\')
885         ds_put_format (out, "\\%c", code);
886       else if (!c_isprint (code))
887         ds_put_format (out, "\\%03o", code);
888       else
889         ds_put_char (out, code); 
890     }
891   ds_put_char (out, ')');
892   return n;
893 }
894
895 /* State of binary encoder for PostScript. */
896 struct binary_encoder
897   {
898     struct string *out;         /* Output string. */
899     uint32_t b;                 /* Accumulated bytes for base-85 encoding. */
900     size_t n;                   /* Number of bytes in b (0...3). */
901   };
902
903 /* Initializes encoder E for output to OUT. */
904 static void
905 binary_init (struct binary_encoder *e, struct string *out) 
906 {
907   e->out = out;
908   e->b = e->n = 0;
909 }
910
911 /* Returns the character that represents VALUE in ASCII85
912    encoding. */
913 static int
914 value_to_ascii85 (int value) 
915 {
916   assert (value >= 0 && value < 85);
917 #if C_CTYPE_ASCII
918   return value + 33;
919 #else
920   return ("!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJK"
921           "LMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu")[value];
922 #endif
923 }
924
925 /* Appends the first N characters of the ASCII85 representation
926    of B to string OUT. */
927 static void
928 append_ascii85_block (unsigned b, size_t n, struct string *out) 
929 {
930   char c[5];
931   int i;
932
933   for (i = 4; i >= 0; i--) 
934     {
935       c[i] = value_to_ascii85 (b % 85);
936       b /= 85; 
937     }
938   ds_put_substring (out, ss_buffer (c, n));
939 }
940
941 /* Encodes BYTE with encoder E. */
942 static void
943 binary_put (struct binary_encoder *e, uint8_t byte) 
944 {
945   e->b = (e->b << 8) | byte;
946   e->n++;
947   if (e->n % 4 == 0)
948     {
949       if (e->n == 4)
950         ds_put_cstr (e->out, "<~");
951
952       if (e->b != 0)
953         append_ascii85_block (e->b, 5, e->out);
954       else 
955         ds_put_char (e->out, 'z');
956     }
957 }
958
959 /* Finishes up encoding with E. */
960 static void
961 binary_finish (struct binary_encoder *e) 
962 {
963   if (e->n >= 4) 
964     {
965       /* We output at least one complete ASCII85 block.
966          Finish up. */
967       size_t n = e->n % 4;
968       if (n > 0)
969         append_ascii85_block (e->b << 8 * (4 - n), n + 1, e->out); 
970       ds_put_cstr (e->out, "~>");
971     }
972   else if (e->n > 0)
973     {
974       /* It's cheaper (or at least the same cost) to encode this
975          string in hexadecimal. */
976       uint32_t b;
977       size_t i;
978
979       ds_put_cstr (e->out, "<");
980       b = e->b << 8 * (4 - e->n);
981       for (i = 0; i < e->n; i++) 
982         {
983           ds_put_format (e->out, "%02x", b >> 24);
984           b <<= 8;
985         }
986       ds_put_cstr (e->out, ">");
987     }
988   else 
989     {
990       /* Empty string. */
991       ds_put_cstr (e->out, "()"); 
992     }
993 }
994
995 /* Encodes the N characters in S into encoder E,
996    using a two-byte encoding.
997    Returns the number of characters remaining after all those
998    that could be successfully encoded were. */
999 static size_t
1000 encode_two_byte (const struct afm_character **s, size_t n,
1001                  struct binary_encoder *e)
1002 {
1003   for (; n > 0; s++, n--) 
1004     {
1005       uint16_t code = (*s)->code;
1006       if (code != (*s)->code)
1007         break;
1008
1009       binary_put (e, code >> 8);
1010       binary_put (e, code);
1011     }
1012   return n;
1013 }
1014
1015 /* Encodes the N characters in S into encoder E,
1016    using an escape-based encoding with ESCAPE_CHAR as escape.
1017    Returns the number of characters remaining after all those
1018    that could be successfully encoded were. */
1019 static size_t
1020 encode_escape (const struct afm_character **s, size_t n,
1021                unsigned char escape_char,
1022                struct binary_encoder *e)
1023 {
1024   uint8_t cur_font = 0;
1025
1026   for (; n > 0; s++, n--)
1027     {
1028       uint16_t code = (*s)->code;
1029       uint8_t font_num = code >> 8;
1030       uint8_t char_num = code & 0xff;
1031       if (code != (*s)->code)
1032         break;
1033
1034       if (font_num != cur_font) 
1035         {
1036           if (font_num == escape_char)
1037             break;
1038           binary_put (e, escape_char);
1039           binary_put (e, font_num);
1040           cur_font = font_num;
1041         }
1042       binary_put (e, char_num);
1043     }
1044   return n;
1045 }
1046
1047 /* Encodes the N characters in S into encoder E,
1048    using an double escape-based encoding with ESCAPE_CHAR as
1049    escape.
1050    Returns the number of characters remaining after all those
1051    that could be successfully encoded were. */
1052 static size_t
1053 encode_double_escape (const struct afm_character **s, size_t n,
1054                       unsigned char escape_char,
1055                       struct binary_encoder *e)
1056 {
1057   unsigned cur_font = 0;
1058
1059   for (; n > 0; s++, n--)
1060     {
1061       unsigned font_num = (*s)->code >> 8;
1062       uint8_t char_num = (*s)->code & 0xff;
1063       if ((*s)->code & ~0x1ffff)
1064         break;
1065
1066       if (font_num != cur_font) 
1067         {
1068           if (font_num == (escape_char & 0xff))
1069             break;
1070           if (font_num >= 256)
1071             binary_put (e, escape_char);
1072           binary_put (e, escape_char);
1073           binary_put (e, font_num & 0xff);
1074           cur_font = font_num;
1075         }
1076       binary_put (e, char_num);
1077     }
1078   return n;
1079 }
1080
1081 /* Encodes the N characters in S into encoder E,
1082    using a shift-based encoding with SHIFT_IN and SHIFT_OUT as
1083    shift characters.
1084    Returns the number of characters remaining after all those
1085    that could be successfully encoded were. */
1086 static size_t
1087 encode_shift (const struct afm_character **s, size_t n,
1088               unsigned char shift_in, unsigned char shift_out,
1089               struct binary_encoder *e)
1090 {
1091   unsigned cur_font = 0;
1092
1093   for (; n > 0; s++, n--)
1094     {
1095       int font_num = ((*s)->code & 0x100) != 0;
1096       uint8_t char_num = (*s)->code & 0xff;
1097       if ((*s)->code & ~0x1ff)
1098         break;
1099
1100       if (font_num != cur_font) 
1101         {
1102           binary_put (e, font_num ? shift_out : shift_in);
1103           cur_font = font_num;
1104         }
1105       binary_put (e, char_num);
1106     }
1107   return n;
1108 }
1109
1110 /* Encodes the N characters in S into a PostScript string in OUT,
1111    according to AFM's character encoding.
1112    Returns the number of characters successfully encoded,
1113    which may be less than N if an unencodable character was
1114    encountered. */
1115 size_t
1116 afm_encode_string (const struct afm *afm,
1117                    const struct afm_character **s, size_t n,
1118                    struct string *out) 
1119 {
1120   size_t initial_length = ds_length (out);
1121   size_t chars_left;
1122
1123   if (afm->mapping == MAP_ONE_BYTE)
1124     chars_left = encode_one_byte (s, n, out);
1125   else 
1126     {
1127       struct binary_encoder e;
1128
1129       binary_init (&e, out);
1130       switch (afm->mapping) 
1131         {
1132         case MAP_TWO_BYTE:
1133           chars_left = encode_two_byte (s, n, &e);
1134           break;
1135
1136         case MAP_ESCAPE:
1137           chars_left = encode_escape (s, n, afm->escape_char, &e);
1138           break;
1139       
1140         case MAP_DOUBLE_ESCAPE:
1141           chars_left = encode_double_escape (s, n, afm->escape_char, &e);
1142           break;
1143
1144         case MAP_SHIFT:
1145           chars_left = encode_shift (s, n, afm->shift_in, afm->shift_out, &e);
1146           break;
1147       
1148         default:
1149           NOT_REACHED ();
1150         }
1151       binary_finish (&e);
1152     }
1153
1154   if (chars_left == n)
1155     ds_truncate (out, initial_length);
1156   return n - chars_left;
1157 }