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/assertion.h>
35 #include <libpspp/pool.h>
36 #include <libpspp/str.h>
39 #define _(msgid) gettext (msgid)
41 /* A kern pair entry. */
44 struct afm_character *successor; /* Second character. */
45 int adjust; /* Adjustment. */
51 struct afm_character *successor; /* Second character. */
52 struct afm_character *ligature; /* Resulting ligature. */
55 /* How to map between byte strings and character values. */
58 MAP_UNKNOWN, /* Not yet determined. */
59 MAP_ONE_BYTE, /* 8-bit coding. */
60 MAP_TWO_BYTE, /* 16-bit coding. */
61 MAP_ESCAPE, /* 8-bit coding with escape to change fonts. */
62 MAP_DOUBLE_ESCAPE, /* 8-bit coding with multiple escapes. */
63 MAP_SHIFT /* 8-bit coding with 2 fonts that toggle. */
69 struct pool *pool; /* Containing pool. */
70 char *findfont_name; /* Name for PostScript /findfont operator. */
71 int ascent; /* Height above the baseline (non-negative). */
72 int descent; /* Depth below the baseline (non-negative). */
74 /* Encoding characters into strings. */
75 enum mapping_scheme mapping; /* Basic mapping scheme. */
76 char escape_char; /* MAP_ESCAPE only: escape character to use. */
77 char shift_out; /* MAP_SHIFT only: selects font 0. */
78 char shift_in; /* MAP_SHIFT only: selects font 1. */
81 struct afm_character *undefined_codes[256];
82 struct afm_character **codes[256];
83 struct afm_character **chars;
87 /* AFM file parser. */
90 struct pool *pool; /* Containing pool. */
91 struct afm *afm; /* AFM being parsed. */
92 FILE *file; /* File being parsed. */
93 const char *file_name; /* Name of file being parsed. */
94 int line_number; /* Current line number in file. */
95 jmp_buf bail_out; /* longjmp() target for error handling. */
97 size_t char_allocated;
101 static struct afm *create_afm (void);
102 static struct afm_character *create_character (struct afm *);
104 static void afm_error (struct parser *, const char *, ...)
108 static void parse_afm (struct parser *);
109 static void skip_section (struct parser *, const char *end_key);
110 static bool parse_set_specific (struct parser *, const char *end_key);
111 static void parse_direction (struct parser *);
112 static void parse_char_metrics (struct parser *);
113 static void parse_kern_pairs (struct parser *);
114 static void add_kern_pair (struct parser *p,
115 struct afm_character *, struct afm_character *,
118 static int skip_spaces (struct parser *);
119 static char *parse_key (struct parser *);
120 static void skip_line (struct parser *);
121 static void force_eol (struct parser *);
122 static bool get_integer (struct parser *, int *);
123 static int force_get_integer (struct parser *);
124 static bool get_number (struct parser *, int *);
125 static int force_get_number (struct parser *);
126 static bool get_hex_code (struct parser *, int *);
127 static int force_get_hex_code (struct parser *);
128 static bool get_word (struct parser *, char **);
129 static char *force_get_word (struct parser *);
130 static bool get_string (struct parser *, char **);
131 static char *force_get_string (struct parser *);
133 static struct afm_character *get_char_by_name (struct parser *, const char *);
134 static struct afm_character *get_char_by_code (const struct afm *, int code);
136 /* Reads FILE_NAME as an AFM file and returns the metrics data.
137 Returns a null pointer if the file cannot be parsed. */
139 afm_open (const char *file_name)
141 struct afm *volatile afm;
142 struct parser *parser;
144 parser = pool_create_container (struct parser, pool);
145 afm = parser->afm = create_afm ();
146 parser->file = pool_fopen (parser->pool, file_name, "r");
147 parser->file_name = file_name;
148 parser->line_number = 0;
149 if (parser->file == NULL)
151 error (0, errno, _("opening font metrics file \"%s\""), file_name);
155 if (setjmp (parser->bail_out))
159 pool_destroy (parser->pool);
163 pool_destroy (parser->pool);
164 pool_destroy (afm->pool);
165 return create_afm ();
168 /* Creates and returns an empty set of metrics. */
173 struct afm_character *def_char;
176 afm = pool_create_container (struct afm, pool);
177 afm->findfont_name = NULL;
180 afm->mapping = MAP_UNKNOWN;
181 afm->escape_char = 255;
184 def_char = create_character (afm);
185 for (i = 0; i < 256; i++)
186 afm->undefined_codes[i] = def_char;
187 for (i = 0; i < 256; i++)
188 afm->codes[i] = afm->undefined_codes;
195 /* Creates and returns an initialized character within AFM. */
196 static struct afm_character *
197 create_character (struct afm *afm)
199 struct afm_character *c = pool_alloc (afm->pool, sizeof *c);
205 c->kern_pairs = NULL;
206 c->kern_pair_cnt = 0;
212 /* Reports the given MESSAGE at the current line in parser P
213 and bails out with longjmp(). */
215 afm_error (struct parser *p, const char *message, ...)
220 va_start (args, message);
221 msg = xasprintf (message, args);
224 error_at_line (0, 0, p->file_name, p->line_number, "%s", msg);
227 longjmp (p->bail_out, 1);
230 /* Parses an AFM file with parser P. */
232 parse_afm (struct parser *p)
236 p->char_allocated = 0;
239 key = force_get_word (p);
240 if (strcmp (key, "StartFontMetrics"))
241 afm_error (p, _("first line must be StartFontMetrics"));
247 if (!strcmp (key, "FontName"))
248 p->afm->findfont_name = pool_strdup (p->afm->pool,
249 force_get_string (p));
250 else if (!strcmp (key, "Ascender"))
251 p->afm->ascent = force_get_integer (p);
252 else if (!strcmp (key, "Descender"))
253 p->afm->descent = force_get_integer (p);
254 else if (!strcmp (key, "MappingScheme"))
256 int scheme = force_get_integer (p);
258 p->afm->mapping = MAP_ONE_BYTE;
259 else if (scheme == 2 || scheme == 5 || scheme == 6)
260 p->afm->mapping = MAP_TWO_BYTE;
261 else if (scheme == 3)
262 p->afm->mapping = MAP_ESCAPE;
263 else if (scheme == 7)
264 p->afm->mapping = MAP_DOUBLE_ESCAPE;
265 else if (scheme == 8)
266 p->afm->mapping = MAP_SHIFT;
268 afm_error (p, _("unsupported MappingScheme %d"), scheme);
270 else if (!strcmp (key, "EscChar"))
271 p->afm->escape_char = force_get_integer (p);
272 else if (!strcmp (key, "StartDirection"))
274 else if (!strcmp (key, "StartCharMetrics"))
275 parse_char_metrics (p);
276 else if (!strcmp (key, "StartKernPairs")
277 || !strcmp (key, "StartKernPairs0"))
278 parse_kern_pairs (p);
279 else if (!strcmp (key, "StartTrackKern"))
280 skip_section (p, "EndTrackKern");
281 else if (!strcmp (key, "StartComposites"))
282 skip_section (p, "EndComposites");
286 while (strcmp (key, "EndFontMetrics"));
288 if (p->afm->findfont_name == NULL)
289 afm_error (p, _("required FontName is missing"));
290 if (p->afm->mapping == MAP_UNKNOWN)
292 /* There seem to be a number of fonts out there that use a
293 2-byte encoding but don't announce it with
295 p->afm->mapping = p->max_code > 255 ? MAP_TWO_BYTE : MAP_ONE_BYTE;
299 /* Reads lines from parser P until one starts with END_KEY. */
301 skip_section (struct parser *p, const char *end_key)
310 while (strcmp (key, end_key));
313 /* Attempts to read an integer from parser P.
314 If one is found, and it is nonzero, skips lines until END_KEY
315 is encountered and returns false.
316 Otherwise, skips the rest of the line and returns true.
317 (This is useful because AFM files can have multiple sets of
318 metrics. Set 0 is for normal text, other sets are for
319 vertical text, etc. We only care about set 0.) */
321 parse_set_specific (struct parser *p, const char *end_key)
325 if (get_integer (p, &set) && set != 0)
327 skip_section (p, end_key);
337 /* Parses a StartDirection...EndDirection section in parser P. */
339 parse_direction (struct parser *p)
343 if (!parse_set_specific (p, "EndDirection"))
349 if (!strcmp (key, "CharWidth"))
350 p->afm->codes[0][0]->width = force_get_integer (p);
353 while (strcmp (key, "EndDirection"));
356 /* Parses a StartCharMetrics...EndCharMetrics section in parser
359 parse_char_metrics (struct parser *p)
361 struct parsing_ligature
363 struct afm_character *first;
368 struct parsing_ligature *ligatures = NULL;
369 size_t ligature_cnt = 0;
370 size_t ligature_allocated = 0;
379 struct afm_character *c;
382 if (!strcmp (key, "EndCharMetrics"))
385 if (p->afm->char_cnt == p->char_allocated)
386 p->afm->chars = pool_2nrealloc (p->afm->pool, p->afm->chars,
388 sizeof *p->afm->chars);
389 c = create_character (p->afm);
391 if (!strcmp (key, "C"))
392 c->code = force_get_integer (p);
393 else if (!strcmp (key, "CH"))
394 c->code = force_get_hex_code (p);
396 afm_error (p, _("CharMetrics line must start with C or CH"));
397 if (c->code < 0 || c->code > 65535)
400 if (c->code > p->max_code)
401 p->max_code = c->code;
403 p->afm->chars[p->afm->char_cnt++] = c;
405 p->afm->codes[c->code >> 8][c->code & 0xff] = c;
407 key = force_get_word (p);
408 while (!strcmp (key, ";"))
410 if (!get_word (p, &key))
413 if (!strcmp (key, "N"))
414 c->name = force_get_word (p);
415 else if (!strcmp (key, "WX") || !strcmp (key, "W0X"))
416 c->width = force_get_number (p);
417 else if (!strcmp (key, "W") || !strcmp (key, "W0"))
419 c->width = force_get_number (p);
420 force_get_number (p);
422 else if (!strcmp (key, "B"))
424 int llx, lly, urx, ury;
425 llx = force_get_number (p);
426 lly = force_get_number (p);
427 urx = force_get_number (p);
428 ury = force_get_number (p);
429 c->ascent = MAX (0, ury);
430 c->descent = MAX (0, -lly);
432 else if (!strcmp (key, "L"))
434 struct parsing_ligature *ligature;
435 if (ligature_cnt == ligature_allocated)
436 ligatures = pool_2nrealloc (p->pool, ligatures,
439 ligature = &ligatures[ligature_cnt++];
441 ligature->successor = force_get_word (p);
442 ligature->ligature = force_get_word (p);
446 while (strcmp (key, ";"))
447 key = force_get_word (p);
450 if (!get_word (p, &key))
456 for (i = 0; i < ligature_cnt; i++)
458 struct parsing_ligature *src = &ligatures[i];
459 struct afm_ligature *dst;
460 src->first->ligatures = pool_nrealloc (p->afm->pool,
461 src->first->ligatures,
462 src->first->ligature_cnt + 1,
463 sizeof *src->first->ligatures);
464 dst = &src->first->ligatures[src->first->ligature_cnt++];
465 dst->successor = get_char_by_name (p, src->successor);
466 dst->ligature = get_char_by_name (p, src->ligature);
470 /* Parses a StartKernPairs...EndKernPairs section in parser P. */
472 parse_kern_pairs (struct parser *p)
480 struct afm_character *c1, *c2;
484 if (!strcmp (key, "KP") || !strcmp (key, "KPX"))
486 c1 = get_char_by_name (p, force_get_word (p));
487 c2 = get_char_by_name (p, force_get_word (p));
488 adjust = force_get_number (p);
489 if (!strcmp (key, "KP"))
490 force_get_number (p);
491 add_kern_pair (p, c1, c2, adjust);
493 else if (!strcmp (key, "KPH"))
495 c1 = get_char_by_code (p->afm, force_get_hex_code (p));
496 c2 = get_char_by_code (p->afm, force_get_hex_code (p));
497 adjust = force_get_number (p);
498 force_get_number (p);
499 add_kern_pair (p, c1, c2, adjust);
504 while (strcmp (key, "EndKernPairs"));
507 /* Adds a kern pair that adjusts (FIRST, SECOND) by ADJUST units
508 to the metrics within parser P. */
510 add_kern_pair (struct parser *p, struct afm_character *first,
511 struct afm_character *second, int adjust)
513 struct afm_kern_pair *kp;
515 first->kern_pairs = pool_nrealloc (p->afm->pool, first->kern_pairs,
516 first->kern_pair_cnt + 1,
517 sizeof *first->kern_pairs);
518 kp = &first->kern_pairs[first->kern_pair_cnt++];
519 kp->successor = second;
523 /* Returns the character with the given NAME with the metrics for
524 parser P. Reports an error if no character has the given
526 static struct afm_character *
527 get_char_by_name (struct parser *p, const char *name)
531 for (i = 0; i < p->afm->char_cnt; i++)
533 struct afm_character *c = p->afm->chars[i];
534 if (c->name != NULL && !strcmp (c->name, name))
537 afm_error (p, _("reference to unknown character \"%s\""), name);
540 /* Returns the character with the given CODE within AFM.
541 Returns a default character if the font doesn't have a
542 character with that code. */
543 static struct afm_character *
544 get_char_by_code (const struct afm *afm, int code_)
546 uint16_t code = code_;
547 return afm->codes[code >> 8][code & 0xff];
550 /* Skips white space, except for new-lines, within parser P. */
552 skip_spaces (struct parser *p)
555 while (isspace (c = getc (p->file)) && c != '\n')
561 /* Parses a word at the beginning of a line.
563 Reports an error if not at the beginning of a line. */
565 parse_key (struct parser *p)
577 while (skip_spaces (p) == '\n');
579 key = force_get_word (p);
580 if (strcmp (key, "Comment"))
587 /* Skips to the next line within parser P. */
589 skip_line (struct parser *p)
593 int c = getc (p->file);
595 afm_error (p, _("expected end of file"));
599 ungetc ('\n', p->file);
602 /* Ensures that parser P is at the end of a line. */
604 force_eol (struct parser *p)
606 if (skip_spaces (p) != '\n')
607 afm_error (p, _("syntax error expecting end of line"));
610 /* Tries to read an integer into *INTEGER at the current position
614 get_integer (struct parser *p, int *integer)
616 int c = skip_spaces (p);
617 if (isdigit (c) || c == '-')
623 tmp = strtol (force_get_word (p), &tail, 10);
624 if (errno == ERANGE || tmp < INT_MIN || tmp > INT_MAX)
625 afm_error (p, _("number out of valid range"));
627 afm_error (p, _("invalid numeric syntax"));
636 /* Returns an integer read from the current position in P.
637 Reports an error if unsuccessful. */
639 force_get_integer (struct parser *p)
642 if (!get_integer (p, &integer))
643 afm_error (p, _("syntax error expecting integer"));
647 /* Tries to read a floating-point number at the current position
648 in parser P. Stores the number's integer part into *INTEGER.
651 get_number (struct parser *p, int *integer)
653 int c = skip_spaces (p);
654 if (c == '-' || c == '.' || isdigit (c))
660 number = c_strtod (force_get_word (p), &tail);
661 if (errno == ERANGE || number < INT_MIN || number > INT_MAX)
662 afm_error (p, _("number out of valid range"));
664 afm_error (p, _("invalid numeric syntax"));
673 /* Returns the integer part of a floating-point number read from
674 the current position in P.
675 Reports an error if unsuccessful. */
677 force_get_number (struct parser *p)
680 if (!get_number (p, &integer))
681 afm_error (p, _("syntax error expecting number"));
685 /* Tries to read an integer expressed in hexadecimal into
689 get_hex_code (struct parser *p, int *integer)
691 if (skip_spaces (p) == '<')
693 if (fscanf (p->file, "<%x", integer) != 1 || getc (p->file) != '>')
694 afm_error (p, _("syntax error in hex constant"));
701 /* Reads an integer expressed in hexadecimal and returns its
703 Reports an error if unsuccessful. */
705 force_get_hex_code (struct parser *p)
708 if (!get_hex_code (p, &integer))
709 afm_error (p, _("syntax error expecting hex constant"));
713 /* Tries to read a word from P into *WORD.
714 The word is allocated in P's pool.
717 get_word (struct parser *p, char **word)
719 if (skip_spaces (p) != '\n')
725 while (!isspace (c = getc (p->file)) && c != EOF)
728 *word = ds_cstr (&s);
729 pool_register (p->pool, free, *word);
739 /* Reads a word from P and returns it.
740 The word is allocated in P's pool.
741 Reports an error if unsuccessful. */
743 force_get_word (struct parser *p)
746 if (!get_word (p, &word))
747 afm_error (p, _("unexpected end of line"));
751 /* Reads a string, consisting of the remainder of the current
752 line, from P, and stores it in *STRING.
753 Leading and trailing spaces are removed.
754 The word is allocated in P's pool.
755 Returns true if a non-empty string was successfully read,
758 get_string (struct parser *p, char **string)
760 struct string s = DS_EMPTY_INITIALIZER;
765 int c = getc (p->file);
766 if (c == EOF || c == '\n')
770 ungetc ('\n', p->file);
771 ds_rtrim (&s, ss_cstr (CC_SPACES));
773 if (!ds_is_empty (&s))
775 *string = ds_cstr (&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,
878 ds_put_char (out, '(');
879 for (; n > 0; s++, n--)
881 uint8_t code = (*s)->code;
882 if (code != (*s)->code)
885 if (code == '(' || code == ')' || code == '\\')
886 ds_put_format (out, "\\%c", code);
887 else if (!c_isprint (code))
888 ds_put_format (out, "\\%03o", code);
890 ds_put_char (out, code);
892 ds_put_char (out, ')');
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_put_substring (out, ss_buffer (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_put_cstr (e->out, "<~");
954 append_ascii85_block (e->b, 5, e->out);
956 ds_put_char (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_put_cstr (e->out, "~>");
975 /* It's cheaper (or at least the same cost) to encode this
976 string in hexadecimal. */
980 ds_put_cstr (e->out, "<");
981 b = e->b << 8 * (4 - e->n);
982 for (i = 0; i < e->n; i++)
984 ds_put_format (e->out, "%02x", b >> 24);
987 ds_put_cstr (e->out, ">");
992 ds_put_cstr (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;