1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2006 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU 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, see <http://www.gnu.org/licenses/>. */
32 #include <libpspp/assertion.h>
33 #include <libpspp/pool.h>
34 #include <libpspp/str.h>
37 #define _(msgid) gettext (msgid)
39 /* A kern pair entry. */
42 struct afm_character *successor; /* Second character. */
43 int adjust; /* Adjustment. */
49 struct afm_character *successor; /* Second character. */
50 struct afm_character *ligature; /* Resulting ligature. */
53 /* How to map between byte strings and character values. */
56 MAP_UNKNOWN, /* Not yet determined. */
57 MAP_ONE_BYTE, /* 8-bit coding. */
58 MAP_TWO_BYTE, /* 16-bit coding. */
59 MAP_ESCAPE, /* 8-bit coding with escape to change fonts. */
60 MAP_DOUBLE_ESCAPE, /* 8-bit coding with multiple escapes. */
61 MAP_SHIFT /* 8-bit coding with 2 fonts that toggle. */
67 struct pool *pool; /* Containing pool. */
68 char *findfont_name; /* Name for PostScript /findfont operator. */
69 int ascent; /* Height above the baseline (non-negative). */
70 int descent; /* Depth below the baseline (non-negative). */
72 /* Encoding characters into strings. */
73 enum mapping_scheme mapping; /* Basic mapping scheme. */
74 char escape_char; /* MAP_ESCAPE only: escape character to use. */
75 char shift_out; /* MAP_SHIFT only: selects font 0. */
76 char shift_in; /* MAP_SHIFT only: selects font 1. */
79 struct afm_character *undefined_codes[256];
80 struct afm_character **codes[256];
81 struct afm_character **chars;
85 /* AFM file parser. */
88 struct pool *pool; /* Containing pool. */
89 struct afm *afm; /* AFM being parsed. */
90 FILE *file; /* File being parsed. */
91 const char *file_name; /* Name of file being parsed. */
92 int line_number; /* Current line number in file. */
93 jmp_buf bail_out; /* longjmp() target for error handling. */
95 size_t char_allocated;
99 static struct afm *create_afm (void);
100 static struct afm_character *create_character (struct afm *);
102 static void afm_error (struct parser *, const char *, ...)
106 static void parse_afm (struct parser *);
107 static void skip_section (struct parser *, const char *end_key);
108 static bool parse_set_specific (struct parser *, const char *end_key);
109 static void parse_direction (struct parser *);
110 static void parse_char_metrics (struct parser *);
111 static void parse_kern_pairs (struct parser *);
112 static void add_kern_pair (struct parser *p,
113 struct afm_character *, struct afm_character *,
116 static int skip_spaces (struct parser *);
117 static char *parse_key (struct parser *);
118 static void skip_line (struct parser *);
119 static void force_eol (struct parser *);
120 static bool get_integer (struct parser *, int *);
121 static int force_get_integer (struct parser *);
122 static bool get_number (struct parser *, int *);
123 static int force_get_number (struct parser *);
124 static bool get_hex_code (struct parser *, int *);
125 static int force_get_hex_code (struct parser *);
126 static bool get_word (struct parser *, char **);
127 static char *force_get_word (struct parser *);
128 static bool get_string (struct parser *, char **);
129 static char *force_get_string (struct parser *);
131 static struct afm_character *get_char_by_name (struct parser *, const char *);
132 static struct afm_character *get_char_by_code (const struct afm *, int code);
134 /* Reads FILE_NAME as an AFM file and returns the metrics data.
135 Returns a null pointer if the file cannot be parsed. */
137 afm_open (const char *file_name)
139 struct afm *volatile afm;
140 struct parser *parser;
142 parser = pool_create_container (struct parser, pool);
143 afm = parser->afm = create_afm ();
144 parser->file = pool_fopen (parser->pool, file_name, "r");
145 parser->file_name = file_name;
146 parser->line_number = 0;
147 if (parser->file == NULL)
149 error (0, errno, _("opening font metrics file \"%s\""), file_name);
153 if (setjmp (parser->bail_out))
157 pool_destroy (parser->pool);
161 pool_destroy (parser->pool);
162 pool_destroy (afm->pool);
163 return create_afm ();
166 /* Creates and returns an empty set of metrics. */
171 struct afm_character *def_char;
174 afm = pool_create_container (struct afm, pool);
175 afm->findfont_name = NULL;
178 afm->mapping = MAP_UNKNOWN;
179 afm->escape_char = 255;
182 def_char = create_character (afm);
183 for (i = 0; i < 256; i++)
184 afm->undefined_codes[i] = def_char;
185 for (i = 0; i < 256; i++)
186 afm->codes[i] = afm->undefined_codes;
193 /* Creates and returns an initialized character within AFM. */
194 static struct afm_character *
195 create_character (struct afm *afm)
197 struct afm_character *c = pool_alloc (afm->pool, sizeof *c);
203 c->kern_pairs = NULL;
204 c->kern_pair_cnt = 0;
210 /* Reports the given MESSAGE at the current line in parser P
211 and bails out with longjmp(). */
213 afm_error (struct parser *p, const char *message, ...)
218 va_start (args, message);
219 msg = xasprintf (message, args);
222 error_at_line (0, 0, p->file_name, p->line_number, "%s", msg);
225 longjmp (p->bail_out, 1);
228 /* Parses an AFM file with parser P. */
230 parse_afm (struct parser *p)
234 p->char_allocated = 0;
237 key = force_get_word (p);
238 if (strcmp (key, "StartFontMetrics"))
239 afm_error (p, _("first line must be StartFontMetrics"));
245 if (!strcmp (key, "FontName"))
246 p->afm->findfont_name = pool_strdup (p->afm->pool,
247 force_get_string (p));
248 else if (!strcmp (key, "Ascender"))
249 p->afm->ascent = force_get_integer (p);
250 else if (!strcmp (key, "Descender"))
251 p->afm->descent = force_get_integer (p);
252 else if (!strcmp (key, "MappingScheme"))
254 int scheme = force_get_integer (p);
256 p->afm->mapping = MAP_ONE_BYTE;
257 else if (scheme == 2 || scheme == 5 || scheme == 6)
258 p->afm->mapping = MAP_TWO_BYTE;
259 else if (scheme == 3)
260 p->afm->mapping = MAP_ESCAPE;
261 else if (scheme == 7)
262 p->afm->mapping = MAP_DOUBLE_ESCAPE;
263 else if (scheme == 8)
264 p->afm->mapping = MAP_SHIFT;
266 afm_error (p, _("unsupported MappingScheme %d"), scheme);
268 else if (!strcmp (key, "EscChar"))
269 p->afm->escape_char = force_get_integer (p);
270 else if (!strcmp (key, "StartDirection"))
272 else if (!strcmp (key, "StartCharMetrics"))
273 parse_char_metrics (p);
274 else if (!strcmp (key, "StartKernPairs")
275 || !strcmp (key, "StartKernPairs0"))
276 parse_kern_pairs (p);
277 else if (!strcmp (key, "StartTrackKern"))
278 skip_section (p, "EndTrackKern");
279 else if (!strcmp (key, "StartComposites"))
280 skip_section (p, "EndComposites");
284 while (strcmp (key, "EndFontMetrics"));
286 if (p->afm->findfont_name == NULL)
287 afm_error (p, _("required FontName is missing"));
288 if (p->afm->mapping == MAP_UNKNOWN)
290 /* There seem to be a number of fonts out there that use a
291 2-byte encoding but don't announce it with
293 p->afm->mapping = p->max_code > 255 ? MAP_TWO_BYTE : MAP_ONE_BYTE;
297 /* Reads lines from parser P until one starts with END_KEY. */
299 skip_section (struct parser *p, const char *end_key)
308 while (strcmp (key, end_key));
311 /* Attempts to read an integer from parser P.
312 If one is found, and it is nonzero, skips lines until END_KEY
313 is encountered and returns false.
314 Otherwise, skips the rest of the line and returns true.
315 (This is useful because AFM files can have multiple sets of
316 metrics. Set 0 is for normal text, other sets are for
317 vertical text, etc. We only care about set 0.) */
319 parse_set_specific (struct parser *p, const char *end_key)
323 if (get_integer (p, &set) && set != 0)
325 skip_section (p, end_key);
335 /* Parses a StartDirection...EndDirection section in parser P. */
337 parse_direction (struct parser *p)
341 if (!parse_set_specific (p, "EndDirection"))
347 if (!strcmp (key, "CharWidth"))
348 p->afm->codes[0][0]->width = force_get_integer (p);
351 while (strcmp (key, "EndDirection"));
354 /* Parses a StartCharMetrics...EndCharMetrics section in parser
357 parse_char_metrics (struct parser *p)
359 struct parsing_ligature
361 struct afm_character *first;
366 struct parsing_ligature *ligatures = NULL;
367 size_t ligature_cnt = 0;
368 size_t ligature_allocated = 0;
377 struct afm_character *c;
380 if (!strcmp (key, "EndCharMetrics"))
383 if (p->afm->char_cnt == p->char_allocated)
384 p->afm->chars = pool_2nrealloc (p->afm->pool, p->afm->chars,
386 sizeof *p->afm->chars);
387 c = create_character (p->afm);
389 if (!strcmp (key, "C"))
390 c->code = force_get_integer (p);
391 else if (!strcmp (key, "CH"))
392 c->code = force_get_hex_code (p);
394 afm_error (p, _("CharMetrics line must start with C or CH"));
395 if (c->code < 0 || c->code > 65535)
398 if (c->code > p->max_code)
399 p->max_code = c->code;
401 p->afm->chars[p->afm->char_cnt++] = c;
403 p->afm->codes[c->code >> 8][c->code & 0xff] = c;
405 key = force_get_word (p);
406 while (!strcmp (key, ";"))
408 if (!get_word (p, &key))
411 if (!strcmp (key, "N"))
412 c->name = force_get_word (p);
413 else if (!strcmp (key, "WX") || !strcmp (key, "W0X"))
414 c->width = force_get_number (p);
415 else if (!strcmp (key, "W") || !strcmp (key, "W0"))
417 c->width = force_get_number (p);
418 force_get_number (p);
420 else if (!strcmp (key, "B"))
422 int llx, lly, urx, ury;
423 llx = force_get_number (p);
424 lly = force_get_number (p);
425 urx = force_get_number (p);
426 ury = force_get_number (p);
427 c->ascent = MAX (0, ury);
428 c->descent = MAX (0, -lly);
430 else if (!strcmp (key, "L"))
432 struct parsing_ligature *ligature;
433 if (ligature_cnt == ligature_allocated)
434 ligatures = pool_2nrealloc (p->pool, ligatures,
437 ligature = &ligatures[ligature_cnt++];
439 ligature->successor = force_get_word (p);
440 ligature->ligature = force_get_word (p);
444 while (strcmp (key, ";"))
445 key = force_get_word (p);
448 if (!get_word (p, &key))
454 for (i = 0; i < ligature_cnt; i++)
456 struct parsing_ligature *src = &ligatures[i];
457 struct afm_ligature *dst;
458 src->first->ligatures = pool_nrealloc (p->afm->pool,
459 src->first->ligatures,
460 src->first->ligature_cnt + 1,
461 sizeof *src->first->ligatures);
462 dst = &src->first->ligatures[src->first->ligature_cnt++];
463 dst->successor = get_char_by_name (p, src->successor);
464 dst->ligature = get_char_by_name (p, src->ligature);
468 /* Parses a StartKernPairs...EndKernPairs section in parser P. */
470 parse_kern_pairs (struct parser *p)
478 struct afm_character *c1, *c2;
482 if (!strcmp (key, "KP") || !strcmp (key, "KPX"))
484 c1 = get_char_by_name (p, force_get_word (p));
485 c2 = get_char_by_name (p, force_get_word (p));
486 adjust = force_get_number (p);
487 if (!strcmp (key, "KP"))
488 force_get_number (p);
489 add_kern_pair (p, c1, c2, adjust);
491 else if (!strcmp (key, "KPH"))
493 c1 = get_char_by_code (p->afm, force_get_hex_code (p));
494 c2 = get_char_by_code (p->afm, force_get_hex_code (p));
495 adjust = force_get_number (p);
496 force_get_number (p);
497 add_kern_pair (p, c1, c2, adjust);
502 while (strcmp (key, "EndKernPairs"));
505 /* Adds a kern pair that adjusts (FIRST, SECOND) by ADJUST units
506 to the metrics within parser P. */
508 add_kern_pair (struct parser *p, struct afm_character *first,
509 struct afm_character *second, int adjust)
511 struct afm_kern_pair *kp;
513 first->kern_pairs = pool_nrealloc (p->afm->pool, first->kern_pairs,
514 first->kern_pair_cnt + 1,
515 sizeof *first->kern_pairs);
516 kp = &first->kern_pairs[first->kern_pair_cnt++];
517 kp->successor = second;
521 /* Returns the character with the given NAME with the metrics for
522 parser P. Reports an error if no character has the given
524 static struct afm_character *
525 get_char_by_name (struct parser *p, const char *name)
529 for (i = 0; i < p->afm->char_cnt; i++)
531 struct afm_character *c = p->afm->chars[i];
532 if (c->name != NULL && !strcmp (c->name, name))
535 afm_error (p, _("reference to unknown character \"%s\""), name);
538 /* Returns the character with the given CODE within AFM.
539 Returns a default character if the font doesn't have a
540 character with that code. */
541 static struct afm_character *
542 get_char_by_code (const struct afm *afm, int code_)
544 uint16_t code = code_;
545 return afm->codes[code >> 8][code & 0xff];
548 /* Skips white space, except for new-lines, within parser P. */
550 skip_spaces (struct parser *p)
553 while (isspace (c = getc (p->file)) && c != '\n')
559 /* Parses a word at the beginning of a line.
561 Reports an error if not at the beginning of a line. */
563 parse_key (struct parser *p)
575 while (skip_spaces (p) == '\n');
577 key = force_get_word (p);
578 if (strcmp (key, "Comment"))
585 /* Skips to the next line within parser P. */
587 skip_line (struct parser *p)
591 int c = getc (p->file);
593 afm_error (p, _("expected end of file"));
597 ungetc ('\n', p->file);
600 /* Ensures that parser P is at the end of a line. */
602 force_eol (struct parser *p)
604 if (skip_spaces (p) != '\n')
605 afm_error (p, _("syntax error expecting end of line"));
608 /* Tries to read an integer into *INTEGER at the current position
612 get_integer (struct parser *p, int *integer)
614 int c = skip_spaces (p);
615 if (isdigit (c) || c == '-')
621 tmp = strtol (force_get_word (p), &tail, 10);
622 if (errno == ERANGE || tmp < INT_MIN || tmp > INT_MAX)
623 afm_error (p, _("number out of valid range"));
625 afm_error (p, _("invalid numeric syntax"));
634 /* Returns an integer read from the current position in P.
635 Reports an error if unsuccessful. */
637 force_get_integer (struct parser *p)
640 if (!get_integer (p, &integer))
641 afm_error (p, _("syntax error expecting integer"));
645 /* Tries to read a floating-point number at the current position
646 in parser P. Stores the number's integer part into *INTEGER.
649 get_number (struct parser *p, int *integer)
651 int c = skip_spaces (p);
652 if (c == '-' || c == '.' || isdigit (c))
658 number = c_strtod (force_get_word (p), &tail);
659 if (errno == ERANGE || number < INT_MIN || number > INT_MAX)
660 afm_error (p, _("number out of valid range"));
662 afm_error (p, _("invalid numeric syntax"));
671 /* Returns the integer part of a floating-point number read from
672 the current position in P.
673 Reports an error if unsuccessful. */
675 force_get_number (struct parser *p)
678 if (!get_number (p, &integer))
679 afm_error (p, _("syntax error expecting number"));
683 /* Tries to read an integer expressed in hexadecimal into
687 get_hex_code (struct parser *p, int *integer)
689 if (skip_spaces (p) == '<')
691 if (fscanf (p->file, "<%x", integer) != 1 || getc (p->file) != '>')
692 afm_error (p, _("syntax error in hex constant"));
699 /* Reads an integer expressed in hexadecimal and returns its
701 Reports an error if unsuccessful. */
703 force_get_hex_code (struct parser *p)
706 if (!get_hex_code (p, &integer))
707 afm_error (p, _("syntax error expecting hex constant"));
711 /* Tries to read a word from P into *WORD.
712 The word is allocated in P's pool.
715 get_word (struct parser *p, char **word)
717 if (skip_spaces (p) != '\n')
723 while (!isspace (c = getc (p->file)) && c != EOF)
726 *word = ds_cstr (&s);
727 pool_register (p->pool, free, *word);
737 /* Reads a word from P and returns it.
738 The word is allocated in P's pool.
739 Reports an error if unsuccessful. */
741 force_get_word (struct parser *p)
744 if (!get_word (p, &word))
745 afm_error (p, _("unexpected end of line"));
749 /* Reads a string, consisting of the remainder of the current
750 line, from P, and stores it in *STRING.
751 Leading and trailing spaces are removed.
752 The word is allocated in P's pool.
753 Returns true if a non-empty string was successfully read,
756 get_string (struct parser *p, char **string)
758 struct string s = DS_EMPTY_INITIALIZER;
763 int c = getc (p->file);
764 if (c == EOF || c == '\n')
768 ungetc ('\n', p->file);
769 ds_rtrim (&s, ss_cstr (CC_SPACES));
771 if (!ds_is_empty (&s))
773 *string = ds_cstr (&s);
774 pool_register (p->pool, free, *string);
785 /* Reads a string, consisting of the remainder of the current
786 line, from P, and returns it.
787 Leading and trailing spaces are removed.
788 The word is allocated in P's pool.
789 Reports an error if the string is empty. */
791 force_get_string (struct parser *p)
794 if (!get_string (p, &string))
795 afm_error (p, _("unexpected end of line expecting string"));
799 /* Closes AFM and frees its storage. */
801 afm_close (struct afm *afm)
804 pool_destroy (afm->pool);
807 /* Returns the string that must be passed to the PostScript
808 "findfont" operator to obtain AFM's font. */
810 afm_get_findfont_name (const struct afm *afm)
812 return afm->findfont_name;
815 /* Returns the ascent for AFM, that is, the font's height above
816 the baseline, in units of 1/1000 of the nominal font size. */
818 afm_get_ascent (const struct afm *afm)
823 /* Returns the descent for AFM, that is, the font's depth below
824 the baseline, in units of 1/1000 of the nominal font size. */
826 afm_get_descent (const struct afm *afm)
831 /* Returns the character numbered CODE within AFM,
832 or a default character if the font has none. */
833 const struct afm_character *
834 afm_get_character (const struct afm *afm, int code)
836 return get_char_by_code (afm, code);
839 /* Returns the ligature formed when FIRST is followed by SECOND,
840 or a null pointer if there is no such ligature. */
841 const struct afm_character *
842 afm_get_ligature (const struct afm_character *first,
843 const struct afm_character *second)
847 for (i = 0; i < first->ligature_cnt; i++)
848 if (first->ligatures[i].successor == second)
849 return first->ligatures[i].ligature;
853 /* Returns the pair kerning x-adjustment when FIRST is followed
854 by SECOND, or 0 if no pair kerning should be done for the
855 given pair of characters. */
857 afm_get_kern_adjustment (const struct afm_character *first,
858 const struct afm_character *second)
862 for (i = 0; i < first->kern_pair_cnt; i++)
863 if (first->kern_pairs[i].successor == second)
864 return first->kern_pairs[i].adjust;
868 /* Encodes the N characters in S as a PostScript string in OUT,
869 using a single-byte encoding.
870 Returns the number of characters remaining after all those
871 that could be successfully encoded were. */
873 encode_one_byte (const struct afm_character **s, size_t n,
876 ds_put_char (out, '(');
877 for (; n > 0; s++, n--)
879 uint8_t code = (*s)->code;
880 if (code != (*s)->code)
883 if (code == '(' || code == ')' || code == '\\')
884 ds_put_format (out, "\\%c", code);
885 else if (!c_isprint (code))
886 ds_put_format (out, "\\%03o", code);
888 ds_put_char (out, code);
890 ds_put_char (out, ')');
894 /* State of binary encoder for PostScript. */
895 struct binary_encoder
897 struct string *out; /* Output string. */
898 uint32_t b; /* Accumulated bytes for base-85 encoding. */
899 size_t n; /* Number of bytes in b (0...3). */
902 /* Initializes encoder E for output to OUT. */
904 binary_init (struct binary_encoder *e, struct string *out)
910 /* Returns the character that represents VALUE in ASCII85
913 value_to_ascii85 (int value)
915 assert (value >= 0 && value < 85);
919 return ("!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJK"
920 "LMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu")[value];
924 /* Appends the first N characters of the ASCII85 representation
925 of B to string OUT. */
927 append_ascii85_block (unsigned b, size_t n, struct string *out)
932 for (i = 4; i >= 0; i--)
934 c[i] = value_to_ascii85 (b % 85);
937 ds_put_substring (out, ss_buffer (c, n));
940 /* Encodes BYTE with encoder E. */
942 binary_put (struct binary_encoder *e, uint8_t byte)
944 e->b = (e->b << 8) | byte;
949 ds_put_cstr (e->out, "<~");
952 append_ascii85_block (e->b, 5, e->out);
954 ds_put_char (e->out, 'z');
958 /* Finishes up encoding with E. */
960 binary_finish (struct binary_encoder *e)
964 /* We output at least one complete ASCII85 block.
968 append_ascii85_block (e->b << 8 * (4 - n), n + 1, e->out);
969 ds_put_cstr (e->out, "~>");
973 /* It's cheaper (or at least the same cost) to encode this
974 string in hexadecimal. */
978 ds_put_cstr (e->out, "<");
979 b = e->b << 8 * (4 - e->n);
980 for (i = 0; i < e->n; i++)
982 ds_put_format (e->out, "%02x", b >> 24);
985 ds_put_cstr (e->out, ">");
990 ds_put_cstr (e->out, "()");
994 /* Encodes the N characters in S into encoder E,
995 using a two-byte encoding.
996 Returns the number of characters remaining after all those
997 that could be successfully encoded were. */
999 encode_two_byte (const struct afm_character **s, size_t n,
1000 struct binary_encoder *e)
1002 for (; n > 0; s++, n--)
1004 uint16_t code = (*s)->code;
1005 if (code != (*s)->code)
1008 binary_put (e, code >> 8);
1009 binary_put (e, code);
1014 /* Encodes the N characters in S into encoder E,
1015 using an escape-based encoding with ESCAPE_CHAR as escape.
1016 Returns the number of characters remaining after all those
1017 that could be successfully encoded were. */
1019 encode_escape (const struct afm_character **s, size_t n,
1020 unsigned char escape_char,
1021 struct binary_encoder *e)
1023 uint8_t cur_font = 0;
1025 for (; n > 0; s++, n--)
1027 uint16_t code = (*s)->code;
1028 uint8_t font_num = code >> 8;
1029 uint8_t char_num = code & 0xff;
1030 if (code != (*s)->code)
1033 if (font_num != cur_font)
1035 if (font_num == escape_char)
1037 binary_put (e, escape_char);
1038 binary_put (e, font_num);
1039 cur_font = font_num;
1041 binary_put (e, char_num);
1046 /* Encodes the N characters in S into encoder E,
1047 using an double escape-based encoding with ESCAPE_CHAR as
1049 Returns the number of characters remaining after all those
1050 that could be successfully encoded were. */
1052 encode_double_escape (const struct afm_character **s, size_t n,
1053 unsigned char escape_char,
1054 struct binary_encoder *e)
1056 unsigned cur_font = 0;
1058 for (; n > 0; s++, n--)
1060 unsigned font_num = (*s)->code >> 8;
1061 uint8_t char_num = (*s)->code & 0xff;
1062 if ((*s)->code & ~0x1ffff)
1065 if (font_num != cur_font)
1067 if (font_num == (escape_char & 0xff))
1069 if (font_num >= 256)
1070 binary_put (e, escape_char);
1071 binary_put (e, escape_char);
1072 binary_put (e, font_num & 0xff);
1073 cur_font = font_num;
1075 binary_put (e, char_num);
1080 /* Encodes the N characters in S into encoder E,
1081 using a shift-based encoding with SHIFT_IN and SHIFT_OUT as
1083 Returns the number of characters remaining after all those
1084 that could be successfully encoded were. */
1086 encode_shift (const struct afm_character **s, size_t n,
1087 unsigned char shift_in, unsigned char shift_out,
1088 struct binary_encoder *e)
1090 unsigned cur_font = 0;
1092 for (; n > 0; s++, n--)
1094 int font_num = ((*s)->code & 0x100) != 0;
1095 uint8_t char_num = (*s)->code & 0xff;
1096 if ((*s)->code & ~0x1ff)
1099 if (font_num != cur_font)
1101 binary_put (e, font_num ? shift_out : shift_in);
1102 cur_font = font_num;
1104 binary_put (e, char_num);
1109 /* Encodes the N characters in S into a PostScript string in OUT,
1110 according to AFM's character encoding.
1111 Returns the number of characters successfully encoded,
1112 which may be less than N if an unencodable character was
1115 afm_encode_string (const struct afm *afm,
1116 const struct afm_character **s, size_t n,
1119 size_t initial_length = ds_length (out);
1122 if (afm->mapping == MAP_ONE_BYTE)
1123 chars_left = encode_one_byte (s, n, out);
1126 struct binary_encoder e;
1128 binary_init (&e, out);
1129 switch (afm->mapping)
1132 chars_left = encode_two_byte (s, n, &e);
1136 chars_left = encode_escape (s, n, afm->escape_char, &e);
1139 case MAP_DOUBLE_ESCAPE:
1140 chars_left = encode_double_escape (s, n, afm->escape_char, &e);
1144 chars_left = encode_shift (s, n, afm->shift_in, afm->shift_out, &e);
1153 if (chars_left == n)
1154 ds_truncate (out, initial_length);
1155 return n - chars_left;