1 /* PSPP - computes sample statistics.
2 Copyright (C) 2006 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
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.
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.
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
34 #include <libpspp/pool.h>
35 #include <libpspp/str.h>
38 #define _(msgid) gettext (msgid)
40 /* A kern pair entry. */
43 struct afm_character *successor; /* Second character. */
44 int adjust; /* Adjustment. */
50 struct afm_character *successor; /* Second character. */
51 struct afm_character *ligature; /* Resulting ligature. */
54 /* How to map between byte strings and character values. */
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. */
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). */
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. */
80 struct afm_character *undefined_codes[256];
81 struct afm_character **codes[256];
82 struct afm_character **chars;
86 /* AFM file parser. */
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. */
96 size_t char_allocated;
100 static struct afm *create_afm (void);
101 static struct afm_character *create_character (struct afm *);
103 static void afm_error (struct parser *, const char *, ...)
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 *,
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 *);
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);
135 /* Reads FILE_NAME as an AFM file and returns the metrics data.
136 Returns a null pointer if the file cannot be parsed. */
138 afm_open (const char *file_name)
140 struct afm *volatile afm;
141 struct parser *parser;
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)
150 error (0, errno, _("opening font metrics file \"%s\""), file_name);
154 if (setjmp (parser->bail_out))
158 pool_destroy (parser->pool);
162 pool_destroy (parser->pool);
163 pool_destroy (afm->pool);
164 return create_afm ();
167 /* Creates and returns an empty set of metrics. */
172 struct afm_character *def_char;
175 afm = pool_create_container (struct afm, pool);
176 afm->findfont_name = NULL;
179 afm->mapping = MAP_UNKNOWN;
180 afm->escape_char = 255;
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;
194 /* Creates and returns an initialized character within AFM. */
195 static struct afm_character *
196 create_character (struct afm *afm)
198 struct afm_character *c = pool_alloc (afm->pool, sizeof *c);
204 c->kern_pairs = NULL;
205 c->kern_pair_cnt = 0;
211 /* Reports the given MESSAGE at the current line in parser P
212 and bails out with longjmp(). */
214 afm_error (struct parser *p, const char *message, ...)
219 va_start (args, message);
220 msg = xasprintf (message, args);
223 error_at_line (0, 0, p->file_name, p->line_number, "%s", msg);
226 longjmp (p->bail_out, 1);
229 /* Parses an AFM file with parser P. */
231 parse_afm (struct parser *p)
235 p->char_allocated = 0;
238 key = force_get_word (p);
239 if (strcmp (key, "StartFontMetrics"))
240 afm_error (p, _("first line must be StartFontMetrics"));
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"))
255 int scheme = force_get_integer (p);
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;
267 afm_error (p, _("unsupported MappingScheme %d"), scheme);
269 else if (!strcmp (key, "EscChar"))
270 p->afm->escape_char = force_get_integer (p);
271 else if (!strcmp (key, "StartDirection"))
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");
285 while (strcmp (key, "EndFontMetrics"));
287 if (p->afm->findfont_name == NULL)
288 afm_error (p, _("required FontName is missing"));
289 if (p->afm->mapping == MAP_UNKNOWN)
291 /* There seem to be a number of fonts out there that use a
292 2-byte encoding but don't announce it with
294 p->afm->mapping = p->max_code > 255 ? MAP_TWO_BYTE : MAP_ONE_BYTE;
298 /* Reads lines from parser P until one starts with END_KEY. */
300 skip_section (struct parser *p, const char *end_key)
309 while (strcmp (key, end_key));
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.) */
320 parse_set_specific (struct parser *p, const char *end_key)
324 if (get_integer (p, &set) && set != 0)
326 skip_section (p, end_key);
336 /* Parses a StartDirection...EndDirection section in parser P. */
338 parse_direction (struct parser *p)
342 if (!parse_set_specific (p, "EndDirection"))
348 if (!strcmp (key, "CharWidth"))
349 p->afm->codes[0][0]->width = force_get_integer (p);
352 while (strcmp (key, "EndDirection"));
355 /* Parses a StartCharMetrics...EndCharMetrics section in parser
358 parse_char_metrics (struct parser *p)
360 struct parsing_ligature
362 struct afm_character *first;
367 struct parsing_ligature *ligatures = NULL;
368 size_t ligature_cnt = 0;
369 size_t ligature_allocated = 0;
378 struct afm_character *c;
381 if (!strcmp (key, "EndCharMetrics"))
384 if (p->afm->char_cnt == p->char_allocated)
385 p->afm->chars = pool_2nrealloc (p->afm->pool, p->afm->chars,
387 sizeof *p->afm->chars);
388 c = create_character (p->afm);
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);
395 afm_error (p, _("CharMetrics line must start with C or CH"));
396 if (c->code < 0 || c->code > 65535)
399 if (c->code > p->max_code)
400 p->max_code = c->code;
402 p->afm->chars[p->afm->char_cnt++] = c;
404 p->afm->codes[c->code >> 8][c->code & 0xff] = c;
406 key = force_get_word (p);
407 while (!strcmp (key, ";"))
409 if (!get_word (p, &key))
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"))
418 c->width = force_get_number (p);
419 force_get_number (p);
421 else if (!strcmp (key, "B"))
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);
431 else if (!strcmp (key, "L"))
433 struct parsing_ligature *ligature;
434 if (ligature_cnt == ligature_allocated)
435 ligatures = pool_2nrealloc (p->pool, ligatures,
438 ligature = &ligatures[ligature_cnt++];
440 ligature->successor = force_get_word (p);
441 ligature->ligature = force_get_word (p);
445 while (strcmp (key, ";"))
446 key = force_get_word (p);
449 if (!get_word (p, &key))
455 for (i = 0; i < ligature_cnt; i++)
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);
469 /* Parses a StartKernPairs...EndKernPairs section in parser P. */
471 parse_kern_pairs (struct parser *p)
479 struct afm_character *c1, *c2;
483 if (!strcmp (key, "KP") || !strcmp (key, "KPX"))
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);
492 else if (!strcmp (key, "KPH"))
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);
503 while (strcmp (key, "EndKernPairs"));
506 /* Adds a kern pair that adjusts (FIRST, SECOND) by ADJUST units
507 to the metrics within parser P. */
509 add_kern_pair (struct parser *p, struct afm_character *first,
510 struct afm_character *second, int adjust)
512 struct afm_kern_pair *kp;
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;
522 /* Returns the character with the given NAME with the metrics for
523 parser P. Reports an error if no character has the given
525 static struct afm_character *
526 get_char_by_name (struct parser *p, const char *name)
530 for (i = 0; i < p->afm->char_cnt; i++)
532 struct afm_character *c = p->afm->chars[i];
533 if (c->name != NULL && !strcmp (c->name, name))
536 afm_error (p, _("reference to unknown character \"%s\""), name);
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_)
545 uint16_t code = code_;
546 return afm->codes[code >> 8][code & 0xff];
549 /* Skips white space, except for new-lines, within parser P. */
551 skip_spaces (struct parser *p)
554 while (isspace (c = getc (p->file)) && c != '\n')
560 /* Parses a word at the beginning of a line.
562 Reports an error if not at the beginning of a line. */
564 parse_key (struct parser *p)
576 while (skip_spaces (p) == '\n');
578 key = force_get_word (p);
579 if (strcmp (key, "Comment"))
586 /* Skips to the next line within parser P. */
588 skip_line (struct parser *p)
592 int c = getc (p->file);
594 afm_error (p, _("expected end of file"));
598 ungetc ('\n', p->file);
601 /* Ensures that parser P is at the end of a line. */
603 force_eol (struct parser *p)
605 if (skip_spaces (p) != '\n')
606 afm_error (p, _("syntax error expecting end of line"));
609 /* Tries to read an integer into *INTEGER at the current position
613 get_integer (struct parser *p, int *integer)
615 int c = skip_spaces (p);
616 if (isdigit (c) || c == '-')
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"));
626 afm_error (p, _("invalid numeric syntax"));
635 /* Returns an integer read from the current position in P.
636 Reports an error if unsuccessful. */
638 force_get_integer (struct parser *p)
641 if (!get_integer (p, &integer))
642 afm_error (p, _("syntax error expecting integer"));
646 /* Tries to read a floating-point number at the current position
647 in parser P. Stores the number's integer part into *INTEGER.
650 get_number (struct parser *p, int *integer)
652 int c = skip_spaces (p);
653 if (c == '-' || c == '.' || isdigit (c))
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"));
663 afm_error (p, _("invalid numeric syntax"));
672 /* Returns the integer part of a floating-point number read from
673 the current position in P.
674 Reports an error if unsuccessful. */
676 force_get_number (struct parser *p)
679 if (!get_number (p, &integer))
680 afm_error (p, _("syntax error expecting number"));
684 /* Tries to read an integer expressed in hexadecimal into
688 get_hex_code (struct parser *p, int *integer)
690 if (skip_spaces (p) == '<')
692 if (fscanf (p->file, "<%x", integer) != 1 || getc (p->file) != '>')
693 afm_error (p, _("syntax error in hex constant"));
700 /* Reads an integer expressed in hexadecimal and returns its
702 Reports an error if unsuccessful. */
704 force_get_hex_code (struct parser *p)
707 if (!get_hex_code (p, &integer))
708 afm_error (p, _("syntax error expecting hex constant"));
712 /* Tries to read a word from P into *WORD.
713 The word is allocated in P's pool.
716 get_word (struct parser *p, char **word)
718 if (skip_spaces (p) != '\n')
724 while (!isspace (c = getc (p->file)) && c != EOF)
727 *word = ds_c_str (&s);
728 pool_register (p->pool, free, *word);
738 /* Reads a word from P and returns it.
739 The word is allocated in P's pool.
740 Reports an error if unsuccessful. */
742 force_get_word (struct parser *p)
745 if (!get_word (p, &word))
746 afm_error (p, _("unexpected end of line"));
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,
757 get_string (struct parser *p, char **string)
765 int c = getc (p->file);
766 if (c == EOF || c == '\n')
770 ungetc ('\n', p->file);
771 ds_rtrim_spaces (&s);
773 if (!ds_is_empty (&s))
775 *string = ds_c_str (&s);
776 pool_register (p->pool, free, *string);
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. */
793 force_get_string (struct parser *p)
796 if (!get_string (p, &string))
797 afm_error (p, _("unexpected end of line expecting string"));
801 /* Closes AFM and frees its storage. */
803 afm_close (struct afm *afm)
806 pool_destroy (afm->pool);
809 /* Returns the string that must be passed to the PostScript
810 "findfont" operator to obtain AFM's font. */
812 afm_get_findfont_name (const struct afm *afm)
814 return afm->findfont_name;
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. */
820 afm_get_ascent (const struct afm *afm)
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. */
828 afm_get_descent (const struct afm *afm)
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)
838 return get_char_by_code (afm, code);
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)
849 for (i = 0; i < first->ligature_cnt; i++)
850 if (first->ligatures[i].successor == second)
851 return first->ligatures[i].ligature;
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. */
859 afm_get_kern_adjustment (const struct afm_character *first,
860 const struct afm_character *second)
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;
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. */
875 encode_one_byte (const struct afm_character **s, size_t n,
879 for (; n > 0; s++, n--)
881 uint8_t code = (*s)->code;
882 if (code != (*s)->code)
885 if (code == '(' || code == ')' || code == '\\')
886 ds_printf (out, "\\%c", code);
887 else if (!c_isprint (code))
888 ds_printf (out, "\\%03o", code);
896 /* State of binary encoder for PostScript. */
897 struct binary_encoder
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). */
904 /* Initializes encoder E for output to OUT. */
906 binary_init (struct binary_encoder *e, struct string *out)
912 /* Returns the character that represents VALUE in ASCII85
915 value_to_ascii85 (int value)
917 assert (value >= 0 && value < 85);
921 return ("!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJK"
922 "LMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu")[value];
926 /* Appends the first N characters of the ASCII85 representation
927 of B to string OUT. */
929 append_ascii85_block (unsigned b, size_t n, struct string *out)
934 for (i = 4; i >= 0; i--)
936 c[i] = value_to_ascii85 (b % 85);
939 ds_concat (out, c, n);
942 /* Encodes BYTE with encoder E. */
944 binary_put (struct binary_encoder *e, uint8_t byte)
946 e->b = (e->b << 8) | byte;
951 ds_puts (e->out, "<~");
954 append_ascii85_block (e->b, 5, e->out);
956 ds_putc (e->out, 'z');
960 /* Finishes up encoding with E. */
962 binary_finish (struct binary_encoder *e)
966 /* We output at least one complete ASCII85 block.
970 append_ascii85_block (e->b << 8 * (4 - n), n + 1, e->out);
971 ds_puts (e->out, "~>");
975 /* It's cheaper (or at least the same cost) to encode this
976 string in hexadecimal. */
980 ds_puts (e->out, "<");
981 b = e->b << 8 * (4 - e->n);
982 for (i = 0; i < e->n; i++)
984 ds_printf (e->out, "%02x", b >> 24);
987 ds_puts (e->out, ">");
992 ds_puts (e->out, "()");
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. */
1001 encode_two_byte (const struct afm_character **s, size_t n,
1002 struct binary_encoder *e)
1004 for (; n > 0; s++, n--)
1006 uint16_t code = (*s)->code;
1007 if (code != (*s)->code)
1010 binary_put (e, code >> 8);
1011 binary_put (e, code);
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. */
1021 encode_escape (const struct afm_character **s, size_t n,
1022 unsigned char escape_char,
1023 struct binary_encoder *e)
1025 uint8_t cur_font = 0;
1027 for (; n > 0; s++, n--)
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)
1035 if (font_num != cur_font)
1037 if (font_num == escape_char)
1039 binary_put (e, escape_char);
1040 binary_put (e, font_num);
1041 cur_font = font_num;
1043 binary_put (e, char_num);
1048 /* Encodes the N characters in S into encoder E,
1049 using an double escape-based encoding with ESCAPE_CHAR as
1051 Returns the number of characters remaining after all those
1052 that could be successfully encoded were. */
1054 encode_double_escape (const struct afm_character **s, size_t n,
1055 unsigned char escape_char,
1056 struct binary_encoder *e)
1058 unsigned cur_font = 0;
1060 for (; n > 0; s++, n--)
1062 unsigned font_num = (*s)->code >> 8;
1063 uint8_t char_num = (*s)->code & 0xff;
1064 if ((*s)->code & ~0x1ffff)
1067 if (font_num != cur_font)
1069 if (font_num == (escape_char & 0xff))
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;
1077 binary_put (e, char_num);
1082 /* Encodes the N characters in S into encoder E,
1083 using a shift-based encoding with SHIFT_IN and SHIFT_OUT as
1085 Returns the number of characters remaining after all those
1086 that could be successfully encoded were. */
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)
1092 unsigned cur_font = 0;
1094 for (; n > 0; s++, n--)
1096 int font_num = ((*s)->code & 0x100) != 0;
1097 uint8_t char_num = (*s)->code & 0xff;
1098 if ((*s)->code & ~0x1ff)
1101 if (font_num != cur_font)
1103 binary_put (e, font_num ? shift_out : shift_in);
1104 cur_font = font_num;
1106 binary_put (e, char_num);
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
1117 afm_encode_string (const struct afm *afm,
1118 const struct afm_character **s, size_t n,
1121 size_t initial_length = ds_length (out);
1124 if (afm->mapping == MAP_ONE_BYTE)
1125 chars_left = encode_one_byte (s, n, out);
1128 struct binary_encoder e;
1130 binary_init (&e, out);
1131 switch (afm->mapping)
1134 chars_left = encode_two_byte (s, n, &e);
1138 chars_left = encode_escape (s, n, afm->escape_char, &e);
1141 case MAP_DOUBLE_ESCAPE:
1142 chars_left = encode_double_escape (s, n, afm->escape_char, &e);
1146 chars_left = encode_shift (s, n, afm->shift_in, afm->shift_out, &e);
1155 if (chars_left == n)
1156 ds_truncate (out, initial_length);
1157 return n - chars_left;