1 /* PSPP - computes sample statistics.
2 Copyright (C) 2006 Free Software Foundation, Inc.
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.
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.
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
33 #include <libpspp/assertion.h>
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_cstr (&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)
759 struct string s = DS_EMPTY_INITIALIZER;
764 int c = getc (p->file);
765 if (c == EOF || c == '\n')
769 ungetc ('\n', p->file);
770 ds_rtrim (&s, ss_cstr (CC_SPACES));
772 if (!ds_is_empty (&s))
774 *string = ds_cstr (&s);
775 pool_register (p->pool, free, *string);
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. */
792 force_get_string (struct parser *p)
795 if (!get_string (p, &string))
796 afm_error (p, _("unexpected end of line expecting string"));
800 /* Closes AFM and frees its storage. */
802 afm_close (struct afm *afm)
805 pool_destroy (afm->pool);
808 /* Returns the string that must be passed to the PostScript
809 "findfont" operator to obtain AFM's font. */
811 afm_get_findfont_name (const struct afm *afm)
813 return afm->findfont_name;
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. */
819 afm_get_ascent (const struct afm *afm)
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. */
827 afm_get_descent (const struct afm *afm)
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)
837 return get_char_by_code (afm, code);
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)
848 for (i = 0; i < first->ligature_cnt; i++)
849 if (first->ligatures[i].successor == second)
850 return first->ligatures[i].ligature;
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. */
858 afm_get_kern_adjustment (const struct afm_character *first,
859 const struct afm_character *second)
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;
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. */
874 encode_one_byte (const struct afm_character **s, size_t n,
877 ds_put_char (out, '(');
878 for (; n > 0; s++, n--)
880 uint8_t code = (*s)->code;
881 if (code != (*s)->code)
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);
889 ds_put_char (out, code);
891 ds_put_char (out, ')');
895 /* State of binary encoder for PostScript. */
896 struct binary_encoder
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). */
903 /* Initializes encoder E for output to OUT. */
905 binary_init (struct binary_encoder *e, struct string *out)
911 /* Returns the character that represents VALUE in ASCII85
914 value_to_ascii85 (int value)
916 assert (value >= 0 && value < 85);
920 return ("!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJK"
921 "LMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu")[value];
925 /* Appends the first N characters of the ASCII85 representation
926 of B to string OUT. */
928 append_ascii85_block (unsigned b, size_t n, struct string *out)
933 for (i = 4; i >= 0; i--)
935 c[i] = value_to_ascii85 (b % 85);
938 ds_put_substring (out, ss_buffer (c, n));
941 /* Encodes BYTE with encoder E. */
943 binary_put (struct binary_encoder *e, uint8_t byte)
945 e->b = (e->b << 8) | byte;
950 ds_put_cstr (e->out, "<~");
953 append_ascii85_block (e->b, 5, e->out);
955 ds_put_char (e->out, 'z');
959 /* Finishes up encoding with E. */
961 binary_finish (struct binary_encoder *e)
965 /* We output at least one complete ASCII85 block.
969 append_ascii85_block (e->b << 8 * (4 - n), n + 1, e->out);
970 ds_put_cstr (e->out, "~>");
974 /* It's cheaper (or at least the same cost) to encode this
975 string in hexadecimal. */
979 ds_put_cstr (e->out, "<");
980 b = e->b << 8 * (4 - e->n);
981 for (i = 0; i < e->n; i++)
983 ds_put_format (e->out, "%02x", b >> 24);
986 ds_put_cstr (e->out, ">");
991 ds_put_cstr (e->out, "()");
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. */
1000 encode_two_byte (const struct afm_character **s, size_t n,
1001 struct binary_encoder *e)
1003 for (; n > 0; s++, n--)
1005 uint16_t code = (*s)->code;
1006 if (code != (*s)->code)
1009 binary_put (e, code >> 8);
1010 binary_put (e, code);
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. */
1020 encode_escape (const struct afm_character **s, size_t n,
1021 unsigned char escape_char,
1022 struct binary_encoder *e)
1024 uint8_t cur_font = 0;
1026 for (; n > 0; s++, n--)
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)
1034 if (font_num != cur_font)
1036 if (font_num == escape_char)
1038 binary_put (e, escape_char);
1039 binary_put (e, font_num);
1040 cur_font = font_num;
1042 binary_put (e, char_num);
1047 /* Encodes the N characters in S into encoder E,
1048 using an double escape-based encoding with ESCAPE_CHAR as
1050 Returns the number of characters remaining after all those
1051 that could be successfully encoded were. */
1053 encode_double_escape (const struct afm_character **s, size_t n,
1054 unsigned char escape_char,
1055 struct binary_encoder *e)
1057 unsigned cur_font = 0;
1059 for (; n > 0; s++, n--)
1061 unsigned font_num = (*s)->code >> 8;
1062 uint8_t char_num = (*s)->code & 0xff;
1063 if ((*s)->code & ~0x1ffff)
1066 if (font_num != cur_font)
1068 if (font_num == (escape_char & 0xff))
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;
1076 binary_put (e, char_num);
1081 /* Encodes the N characters in S into encoder E,
1082 using a shift-based encoding with SHIFT_IN and SHIFT_OUT as
1084 Returns the number of characters remaining after all those
1085 that could be successfully encoded were. */
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)
1091 unsigned cur_font = 0;
1093 for (; n > 0; s++, n--)
1095 int font_num = ((*s)->code & 0x100) != 0;
1096 uint8_t char_num = (*s)->code & 0xff;
1097 if ((*s)->code & ~0x1ff)
1100 if (font_num != cur_font)
1102 binary_put (e, font_num ? shift_out : shift_in);
1103 cur_font = font_num;
1105 binary_put (e, char_num);
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
1116 afm_encode_string (const struct afm *afm,
1117 const struct afm_character **s, size_t n,
1120 size_t initial_length = ds_length (out);
1123 if (afm->mapping == MAP_ONE_BYTE)
1124 chars_left = encode_one_byte (s, n, out);
1127 struct binary_encoder e;
1129 binary_init (&e, out);
1130 switch (afm->mapping)
1133 chars_left = encode_two_byte (s, n, &e);
1137 chars_left = encode_escape (s, n, afm->escape_char, &e);
1140 case MAP_DOUBLE_ESCAPE:
1141 chars_left = encode_double_escape (s, n, afm->escape_char, &e);
1145 chars_left = encode_shift (s, n, afm->shift_in, afm->shift_out, &e);
1154 if (chars_left == n)
1155 ds_truncate (out, initial_length);
1156 return n - chars_left;