summaryrefslogtreecommitdiff
path: root/Build/source/texk/dvipdfm-x/cs_type2.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/dvipdfm-x/cs_type2.c')
-rw-r--r--Build/source/texk/dvipdfm-x/cs_type2.c807
1 files changed, 807 insertions, 0 deletions
diff --git a/Build/source/texk/dvipdfm-x/cs_type2.c b/Build/source/texk/dvipdfm-x/cs_type2.c
new file mode 100644
index 00000000000..fcb3edf4805
--- /dev/null
+++ b/Build/source/texk/dvipdfm-x/cs_type2.c
@@ -0,0 +1,807 @@
+/*
+
+ This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
+
+ Copyright (C) 2002-2012 by Jin-Hwan Cho and Shunsaku Hirata,
+ the dvipdfmx project team.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+*/
+
+/*
+ * Type 2 Charstring support:
+ * Decode and encode Type 2 charstring
+ *
+ * All local/global subroutine calls in a given charstring is replace by the
+ * content of subroutine charstrings. We do this because some PostScript RIP
+ * may have problems with sparse subroutine array. Workaround for this is to
+ * re-order subroutine array so that no gap appears in the subroutine array,
+ * or put dummy charstrings that contains only `return' in the gap. However,
+ * re-ordering of subroutine is rather difficult for Type 2 charstrings due
+ * to the bias which depends on the total number of subroutines. Replacing
+ * callgsubr/callsubr calls with the content of the corresponding subroutine
+ * charstring may be more efficient than putting dummy subroutines in the
+ * case of subsetted font. Adobe distiller seems doing same thing.
+ *
+ * And also note that subroutine numbers within subroutines can depend on the
+ * content of operand stack as follows:
+ *
+ * ... l m callsubr << subr #(m+bias): n add callsubr >> ...
+ *
+ * I've not implemented the `random' operator which generates a pseudo-random
+ * number in the range (0, 1] and push them into argument stack.
+ * How pseudo-random sequences are generated is not documented in the Type 2
+ * charstring spec..
+ */
+
+#include <stdio.h>
+
+/* fabs, sqrt ... */
+#include <math.h>
+
+#include "error.h"
+
+/* data types, limits */
+#include "cff_types.h"
+#include "cff_limits.h"
+
+#include "cs_type2.h"
+
+#define CS_TYPE2_DEBUG_STR "Type2 Charstring Parser"
+#define CS_TYPE2_DEBUG 5
+
+/* decoder/encoder status codes */
+#define CS_BUFFER_ERROR -3
+#define CS_STACK_ERROR -2
+#define CS_PARSE_ERROR -1
+#define CS_PARSE_OK 0
+#define CS_PARSE_END 1
+#define CS_SUBR_RETURN 2
+#define CS_CHAR_END 3
+
+static int status = CS_PARSE_ERROR;
+
+#define DST_NEED(a,b) {if ((a) < (b)) { status = CS_BUFFER_ERROR ; return ; }}
+#define SRC_NEED(a,b) {if ((a) < (b)) { status = CS_PARSE_ERROR ; return ; }}
+#define NEED(a,b) {if ((a) < (b)) { status = CS_STACK_ERROR ; return ; }}
+
+/* hintmask and cntrmask need number of stem zones */
+static int num_stems = 0;
+static int phase = 0;
+
+/* subroutine nesting */
+static int nest = 0;
+
+/* advance width */
+static int have_width = 0;
+static double width = 0.0;
+
+/*
+ * Standard Encoding Accented Characters:
+ * Optional four arguments for endchar. See, CFF spec., p.35.
+ * This is obsolete feature and is no longer supported.
+ */
+#if 0
+/* adx ady bchar achar endchar */
+static double seac[4] = {0.0, 0.0, 0.0, 0.0};
+#endif
+
+/* Operand stack and Transient array */
+static int stack_top = 0;
+static double arg_stack[CS_ARG_STACK_MAX];
+static double trn_array[CS_TRANS_ARRAY_MAX];
+
+/*
+ * Type 2 CharString encoding
+ */
+
+/*
+ * 1-byte CharString operaotrs:
+ * cs_escape is first byte of two-byte operator
+ */
+
+/* RESERVED 0 */
+#define cs_hstem 1
+/* RESERVED 2 */
+#define cs_vstem 3
+#define cs_vmoveto 4
+#define cs_rlineto 5
+#define cs_hlineto 6
+#define cs_vlineto 7
+#define cs_rrcurveto 8
+/* cs_closepath 9 : TYPE1 */
+#define cs_callsubr 10
+#define cs_return 11
+#define cs_escape 12
+/* cs_hsbw 13 : TYPE1 */
+#define cs_endchar 14
+/* RESERVED 15 */
+/* RESERVED 16 */
+/* RESERVED 17 */
+#define cs_hstemhm 18
+#define cs_hintmask 19
+#define cs_cntrmask 20
+#define cs_rmoveto 21
+#define cs_hmoveto 22
+#define cs_vstemhm 23
+#define cs_rcurveline 24
+#define cs_rlinecurve 25
+#define cs_vvcurveto 26
+#define cs_hhcurveto 27
+/* SHORTINT 28 : first byte of shortint*/
+#define cs_callgsubr 29
+#define cs_vhcurveto 30
+#define cs_hvcurveto 31
+
+/*
+ * 2-byte CharString operaotrs:
+ * "dotsection" is obsoleted in Type 2 charstring.
+ */
+
+#define cs_dotsection 0
+/* cs_vstem3 1 : TYPE1 */
+/* cs_hstem3 2 : TYPE1 */
+#define cs_and 3
+#define cs_or 4
+#define cs_not 5
+/* cs_seac 6 : TYPE1 */
+/* cs_sbw 7 : TYPE1 */
+/* RESERVED 8 */
+#define cs_abs 9
+#define cs_add 10
+#define cs_sub 11
+#define cs_div 12
+/* RESERVED 13 */
+#define cs_neg 14
+#define cs_eq 15
+/* cs_callothersubr 16 : TYPE1 */
+/* cs_pop 17 : TYPE1 */
+#define cs_drop 18
+/* RESERVED 19 */
+#define cs_put 20
+#define cs_get 21
+#define cs_ifelse 22
+#define cs_random 23
+#define cs_mul 24
+/* RESERVED 25 */
+#define cs_sqrt 26
+#define cs_dup 27
+#define cs_exch 28
+#define cs_index 29
+#define cs_roll 30
+/* cs_setcurrentpoint 31 : TYPE1 */
+/* RESERVED 32 */
+/* RESERVED 33 */
+#define cs_hflex 34
+#define cs_flex 35
+#define cs_hflex1 36
+#define cs_flex1 37
+
+/*
+ * clear_stack() put all operands sotred in operand stack to dest.
+ */
+static void
+clear_stack (card8 **dest, card8 *limit)
+{
+ int i;
+
+ for (i = 0; i < stack_top; i++) {
+ double value;
+ long ivalue;
+ value = arg_stack[i];
+ /* Nearest integer value */
+ ivalue = (long) floor(value+0.5);
+ if (value >= 0x8000L || value <= (-0x8000L - 1)) {
+ /*
+ * This number cannot be represented as a single operand.
+ * We must use `a b mul ...' or `a c div' to represent large values.
+ */
+ ERROR("%s: Argument value too large. (This is bug)", CS_TYPE2_DEBUG_STR);
+ } else if (fabs(value - ivalue) > 3.0e-5) {
+ /* 16.16-bit signed fixed value */
+ DST_NEED(limit, *dest + 5);
+ *(*dest)++ = 255;
+ ivalue = (long) floor(value); /* mantissa */
+ *(*dest)++ = (ivalue >> 8) & 0xff;
+ *(*dest)++ = ivalue & 0xff;
+ ivalue = (long)((value - ivalue) * 0x10000l); /* fraction */
+ *(*dest)++ = (ivalue >> 8) & 0xff;
+ *(*dest)++ = ivalue & 0xff;
+ /* Everything else are integers. */
+ } else if (ivalue >= -107 && ivalue <= 107) {
+ DST_NEED(limit, *dest + 1);
+ *(*dest)++ = ivalue + 139;
+ } else if (ivalue >= 108 && ivalue <= 1131) {
+ DST_NEED(limit, *dest + 2);
+ ivalue = 0xf700u + ivalue - 108;
+ *(*dest)++ = (ivalue >> 8) & 0xff;
+ *(*dest)++ = ivalue & 0xff;
+ } else if (ivalue >= -1131 && ivalue <= -108) {
+ DST_NEED(limit, *dest + 2);
+ ivalue = 0xfb00u - ivalue - 108;
+ *(*dest)++ = (ivalue >> 8) & 0xff;
+ *(*dest)++ = ivalue & 0xff;
+ } else if (ivalue >= -32768 && ivalue <= 32767) { /* shortint */
+ DST_NEED(limit, *dest + 3);
+ *(*dest)++ = 28;
+ *(*dest)++ = (ivalue >> 8) & 0xff;
+ *(*dest)++ = (ivalue) & 0xff;
+ } else { /* Shouldn't come here */
+ ERROR("%s: Unexpected error.", CS_TYPE2_DEBUG_STR);
+ }
+ }
+
+ stack_top = 0; /* clear stack */
+
+ return;
+}
+
+/*
+ * Single byte operators:
+ * Path construction, Operator for finishing a path, Hint operators.
+ *
+ * phase:
+ * 0: inital state
+ * 1: hint declaration, first stack-clearing operator appeared
+ * 2: in path construction
+ */
+
+static void
+do_operator1 (card8 **dest, card8 *limit, card8 **data, card8 *endptr)
+{
+ card8 op = **data;
+
+ *data += 1;
+
+ switch (op) {
+ case cs_hstemhm:
+ case cs_vstemhm:
+ /* charstring may have hintmask if above operator have seen */
+ case cs_hstem:
+ case cs_vstem:
+ if (phase == 0 && (stack_top % 2)) {
+ have_width = 1;
+ width = arg_stack[0];
+ }
+ num_stems += stack_top/2;
+ clear_stack(dest, limit);
+ DST_NEED(limit, *dest + 1);
+ *(*dest)++ = op;
+ phase = 1;
+ break;
+ case cs_hintmask:
+ case cs_cntrmask:
+ if (phase < 2) {
+ if (phase == 0 && (stack_top % 2)) {
+ have_width = 1;
+ width = arg_stack[0];
+ }
+ num_stems += stack_top/2;
+ }
+ clear_stack(dest, limit);
+ DST_NEED(limit, *dest + 1);
+ *(*dest)++ = op;
+ if (num_stems > 0) {
+ int masklen = (num_stems + 7) / 8;
+ DST_NEED(limit, *dest + masklen);
+ SRC_NEED(endptr, *data + masklen);
+ memmove(*dest, *data, masklen);
+ *data += masklen;
+ *dest += masklen;
+ }
+ phase = 2;
+ break;
+ case cs_rmoveto:
+ if (phase == 0 && (stack_top % 2)) {
+ have_width = 1;
+ width = arg_stack[0];
+ }
+ clear_stack(dest, limit);
+ DST_NEED(limit, *dest + 1);
+ *(*dest)++ = op;
+ phase = 2;
+ break;
+ case cs_hmoveto:
+ case cs_vmoveto:
+ if (phase == 0 && (stack_top % 2) == 0) {
+ have_width = 1;
+ width = arg_stack[0];
+ }
+ clear_stack(dest, limit);
+ DST_NEED(limit, *dest + 1);
+ *(*dest)++ = op;
+ phase = 2;
+ break;
+ case cs_endchar:
+ if (stack_top == 1) {
+ have_width = 1;
+ width = arg_stack[0];
+ clear_stack(dest, limit);
+ } else if (stack_top == 4 || stack_top == 5) {
+ WARN("\"seac\" character deprecated in Type 2 charstring.");
+ status = CS_PARSE_ERROR;
+ return;
+ } else if (stack_top > 0) {
+ WARN("%s: Operand stack not empty.", CS_TYPE2_DEBUG_STR);
+ }
+ DST_NEED(limit, *dest + 1);
+ *(*dest)++ = op;
+ status = CS_CHAR_END;
+ break;
+ /* above oprators are candidate for first stack-clearing operator */
+ case cs_rlineto:
+ case cs_hlineto:
+ case cs_vlineto:
+ case cs_rrcurveto:
+ case cs_rcurveline:
+ case cs_rlinecurve:
+ case cs_vvcurveto:
+ case cs_hhcurveto:
+ case cs_vhcurveto:
+ case cs_hvcurveto:
+ if (phase < 2) {
+ WARN("%s: Broken Type 2 charstring.", CS_TYPE2_DEBUG_STR);
+ status = CS_PARSE_ERROR;
+ return;
+ }
+ clear_stack(dest, limit);
+ DST_NEED(limit, *dest + 1);
+ *(*dest)++ = op;
+ break;
+ /* all operotors above are stack-clearing operator */
+ /* no output */
+ case cs_return:
+ case cs_callgsubr:
+ case cs_callsubr:
+ ERROR("%s: Unexpected call(g)subr/return", CS_TYPE2_DEBUG_STR);
+ break;
+ default:
+ /* no-op ? */
+ WARN("%s: Unknown charstring operator: 0x%02x", CS_TYPE2_DEBUG_STR, op);
+ status = CS_PARSE_ERROR;
+ break;
+ }
+
+ return;
+}
+
+/*
+ * Double byte operators:
+ * Flex, arithmetic, conditional, and storage operators.
+ *
+ * Following operators are not supported:
+ * random: How random ?
+ */
+static void
+do_operator2 (card8 **dest, card8 *limit, card8 **data, card8 *endptr)
+{
+ card8 op;
+
+ *data += 1;
+
+ SRC_NEED(endptr, *data + 1);
+
+ op = **data;
+ *data += 1;
+
+ switch(op) {
+ case cs_dotsection: /* deprecated */
+ WARN("Operator \"dotsection\" deprecated in Type 2 charstring.");
+ status = CS_PARSE_ERROR;
+ return;
+ break;
+ case cs_hflex:
+ case cs_flex:
+ case cs_hflex1:
+ case cs_flex1:
+ if (phase < 2) {
+ WARN("%s: Broken Type 2 charstring.", CS_TYPE2_DEBUG_STR);
+ status = CS_PARSE_ERROR;
+ return;
+ }
+ clear_stack(dest, limit);
+ DST_NEED(limit, *dest + 2);
+ *(*dest)++ = cs_escape;
+ *(*dest)++ = op;
+ break;
+ /* all operator above are stack-clearing */
+ /* no output */
+ case cs_and:
+ NEED(stack_top, 2);
+ stack_top--;
+ if (arg_stack[stack_top] && arg_stack[stack_top-1]) {
+ arg_stack[stack_top-1] = 1.0;
+ } else {
+ arg_stack[stack_top-1] = 0.0;
+ }
+ break;
+ case cs_or:
+ NEED(stack_top, 2);
+ stack_top--;
+ if (arg_stack[stack_top] || arg_stack[stack_top-1]) {
+ arg_stack[stack_top-1] = 1.0;
+ } else {
+ arg_stack[stack_top-1] = 0.0;
+ }
+ break;
+ case cs_not:
+ NEED(stack_top, 1);
+ if (arg_stack[stack_top-1]) {
+ arg_stack[stack_top-1] = 0.0;
+ } else {
+ arg_stack[stack_top-1] = 1.0;
+ }
+ break;
+ case cs_abs:
+ NEED(stack_top, 1);
+ arg_stack[stack_top-1] = fabs(arg_stack[stack_top-1]);
+ break;
+ case cs_add:
+ NEED(stack_top, 2);
+ arg_stack[stack_top-2] += arg_stack[stack_top-1];
+ stack_top--;
+ break;
+ case cs_sub:
+ NEED(stack_top, 2);
+ arg_stack[stack_top-2] -= arg_stack[stack_top-1];
+ stack_top--;
+ break;
+ case cs_div: /* doesn't check overflow */
+ NEED(stack_top, 2);
+ arg_stack[stack_top-2] /= arg_stack[stack_top-1];
+ stack_top--;
+ break;
+ case cs_neg:
+ NEED(stack_top, 1);
+ arg_stack[stack_top-1] *= -1.0;
+ break;
+ case cs_eq:
+ NEED(stack_top, 2);
+ stack_top--;
+ if (arg_stack[stack_top] == arg_stack[stack_top-1]) {
+ arg_stack[stack_top-1] = 1.0;
+ } else {
+ arg_stack[stack_top-1] = 0.0;
+ }
+ break;
+ case cs_drop:
+ NEED(stack_top, 1);
+ stack_top--;
+ break;
+ case cs_put:
+ NEED(stack_top, 2);
+ {
+ int idx = (int)arg_stack[--stack_top];
+ NEED(CS_TRANS_ARRAY_MAX, idx);
+ trn_array[idx] = arg_stack[--stack_top];
+ }
+ break;
+ case cs_get:
+ NEED(stack_top, 1);
+ {
+ int idx = (int)arg_stack[stack_top-1];
+ NEED(CS_TRANS_ARRAY_MAX, idx);
+ arg_stack[stack_top-1] = trn_array[idx];
+ }
+ break;
+ case cs_ifelse:
+ NEED(stack_top, 4);
+ stack_top -= 3;
+ if (arg_stack[stack_top+1] > arg_stack[stack_top+2]) {
+ arg_stack[stack_top-1] = arg_stack[stack_top];
+ }
+ break;
+ case cs_mul:
+ NEED(stack_top, 2);
+ arg_stack[stack_top-2] = arg_stack[stack_top-2] * arg_stack[stack_top-1];
+ stack_top--;
+ break;
+ case cs_sqrt:
+ NEED(stack_top, 1);
+ arg_stack[stack_top-1] = sqrt(arg_stack[stack_top-1]);
+ break;
+ case cs_dup:
+ NEED(stack_top, 1);
+ NEED(CS_ARG_STACK_MAX, stack_top+1);
+ arg_stack[stack_top] = arg_stack[stack_top-1];
+ stack_top++;
+ break;
+ case cs_exch:
+ NEED(stack_top, 2);
+ {
+ double save = arg_stack[stack_top-2];
+ arg_stack[stack_top-2] = arg_stack[stack_top-1];
+ arg_stack[stack_top-1] = save;
+ }
+ break;
+ case cs_index:
+ NEED(stack_top, 2); /* need two arguments at least */
+ {
+ int idx = (int)arg_stack[stack_top-1];
+ if (idx < 0) {
+ arg_stack[stack_top-1] = arg_stack[stack_top-2];
+ } else {
+ NEED(stack_top, idx+2);
+ arg_stack[stack_top-1] = arg_stack[stack_top-idx-2];
+ }
+ }
+ break;
+ case cs_roll:
+ NEED(stack_top, 2);
+ {
+ int N, J;
+ J = (int)arg_stack[--stack_top];
+ N = (int)arg_stack[--stack_top];
+ NEED(stack_top, N);
+ if (J > 0) {
+ J = J % N;
+ while (J-- > 0) {
+ double save = arg_stack[stack_top-1];
+ int i = stack_top - 1;
+ while (i > stack_top-N) {
+ arg_stack[i] = arg_stack[i-1];
+ i--;
+ }
+ arg_stack[i] = save;
+ }
+ } else {
+ J = (-J) % N;
+ while (J-- > 0) {
+ double save = arg_stack[stack_top-N];
+ int i = stack_top - N;
+ while (i < stack_top-1) {
+ arg_stack[i] = arg_stack[i+1];
+ i++;
+ }
+ arg_stack[i] = save;
+ }
+ }
+ }
+ break;
+ case cs_random:
+ WARN("%s: Charstring operator \"random\" found.", CS_TYPE2_DEBUG_STR);
+ NEED(CS_ARG_STACK_MAX, stack_top+1);
+ arg_stack[stack_top++] = 1.0;
+ break;
+ default:
+ /* no-op ? */
+ WARN("%s: Unknown charstring operator: 0x0c%02x", CS_TYPE2_DEBUG_STR, op);
+ status = CS_PARSE_ERROR;
+ break;
+ }
+
+ return;
+}
+
+/*
+ * integer:
+ * exactly the same as the DICT encoding (except 29)
+ */
+static void
+get_integer (card8 **data, card8 *endptr)
+{
+ long result = 0;
+ card8 b0 = **data, b1, b2;
+
+ *data += 1;
+
+ if (b0 == 28) { /* shortint */
+ SRC_NEED(endptr, *data + 2);
+ b1 = **data;
+ b2 = *(*data+1);
+ result = b1*256+b2;
+ if (result > 0x7fff)
+ result -= 0x10000L;
+ *data += 2;
+ } else if (b0 >= 32 && b0 <= 246) { /* int (1) */
+ result = b0 - 139;
+ } else if (b0 >= 247 && b0 <= 250) { /* int (2) */
+ SRC_NEED(endptr, *data + 1);
+ b1 = **data;
+ result = (b0-247)*256+b1+108;
+ *data += 1;
+ } else if (b0 >= 251 && b0 <= 254) {
+ SRC_NEED(endptr, *data + 1);
+ b1 = **data;
+ result = -(b0-251)*256-b1-108;
+ *data += 1;
+ } else {
+ status = CS_PARSE_ERROR;
+ return;
+ }
+
+ NEED(CS_ARG_STACK_MAX, stack_top+1);
+ arg_stack[stack_top++] = (double) result;
+
+ return;
+}
+
+/*
+ * Signed 16.16-bits fixed number for Type 2 charstring encoding
+ */
+static void
+get_fixed (card8 **data, card8 *endptr)
+{
+ long ivalue;
+ double rvalue;
+
+ *data += 1;
+
+ SRC_NEED(endptr, *data + 4);
+
+ ivalue = *(*data) * 0x100 + *(*data+1);
+ rvalue = (ivalue > 0x7fffL) ? (ivalue - 0x10000L) : ivalue;
+ ivalue = *(*data+2) * 0x100 + *(*data+3);
+ rvalue += ((double) ivalue) / 0x10000L;
+
+ NEED(CS_ARG_STACK_MAX, stack_top+1);
+ arg_stack[stack_top++] = rvalue;
+ *data += 4;
+
+ return;
+}
+
+/*
+ * Subroutines:
+ * The bias for subroutine number is introduced in type 2 charstrings.
+ *
+ * subr: set to a pointer to the subroutine charstring.
+ * len: set to the length of subroutine charstring.
+ * subr_idx: CFF INDEX data that contains subroutines.
+ * id: biased subroutine number.
+ */
+static void
+get_subr (card8 **subr, long *len, cff_index *subr_idx, long id)
+{
+ card16 count;
+
+ if (subr_idx == NULL)
+ ERROR("%s: Subroutine called but no subroutine found.", CS_TYPE2_DEBUG_STR);
+
+ count = subr_idx->count;
+
+ /* Adding bias number */
+ if (count < 1240) {
+ id += 107;
+ } else if (count < 33900) {
+ id += 1131;
+ } else {
+ id += 32768;
+ }
+
+ if (id > count)
+ ERROR("%s: Invalid Subr index: %ld (max=%u)", CS_TYPE2_DEBUG_STR, id, count);
+
+ *len = (subr_idx->offset)[id + 1] - (subr_idx->offset)[id];
+ *subr = subr_idx->data + (subr_idx->offset)[id] - 1;
+
+ return;
+}
+
+/*
+ * NOTE:
+ * The Type 2 interpretation of a number encoded in five-bytes (those with
+ * an initial byte value of 255) differs from how it is interpreted in the
+ * Type 1 format.
+ */
+
+static void
+do_charstring (card8 **dest, card8 *limit,
+ card8 **data, card8 *endptr,
+ cff_index *gsubr_idx, cff_index *subr_idx)
+{
+ card8 b0 = 0, *subr;
+ long len;
+
+ if (nest > CS_SUBR_NEST_MAX)
+ ERROR("%s: Subroutine nested too deeply.", CS_TYPE2_DEBUG_STR);
+
+ nest++;
+
+ while (*data < endptr && status == CS_PARSE_OK) {
+ b0 = **data;
+ if (b0 == 255) { /* 16-bit.16-bit fixed signed number */
+ get_fixed(data, endptr);
+ } else if (b0 == cs_return) {
+ status = CS_SUBR_RETURN;
+ } else if (b0 == cs_callgsubr) {
+ if (stack_top < 1) {
+ status = CS_STACK_ERROR;
+ } else {
+ stack_top--;
+ get_subr(&subr, &len, gsubr_idx, (long) arg_stack[stack_top]);
+ if (*dest + len > limit)
+ ERROR("%s: Possible buffer overflow.", CS_TYPE2_DEBUG_STR);
+ do_charstring(dest, limit, &subr, subr + len,
+ gsubr_idx, subr_idx);
+ *data += 1;
+ }
+ } else if (b0 == cs_callsubr) {
+ if (stack_top < 1) {
+ status = CS_STACK_ERROR;
+ } else {
+ stack_top--;
+ get_subr(&subr, &len, subr_idx, (long) arg_stack[stack_top]);
+ if (limit < *dest + len)
+ ERROR("%s: Possible buffer overflow.", CS_TYPE2_DEBUG_STR);
+ do_charstring(dest, limit, &subr, subr + len,
+ gsubr_idx, subr_idx);
+ *data += 1;
+ }
+ } else if (b0 == cs_escape) {
+ do_operator2(dest, limit, data, endptr);
+ } else if (b0 < 32 && b0 != 28) { /* 19, 20 need mask */
+ do_operator1(dest, limit, data, endptr);
+ } else if ((b0 <= 22 && b0 >= 27) || b0 == 31) { /* reserved */
+ status = CS_PARSE_ERROR; /* not an error ? */
+ } else { /* integer */
+ get_integer(data, endptr);
+ }
+ }
+
+ if (status == CS_SUBR_RETURN) {
+ status = CS_PARSE_OK;
+ } else if (status == CS_CHAR_END && *data < endptr) {
+ WARN("%s: Garbage after endchar.", CS_TYPE2_DEBUG_STR);
+ } else if (status < CS_PARSE_OK) { /* error */
+ ERROR("%s: Parsing charstring failed: (status=%d, stack=%d)",
+ CS_TYPE2_DEBUG_STR, status, stack_top);
+ }
+
+ nest--;
+
+ return;
+}
+
+static void
+cs_parse_init (void)
+{
+ status = CS_PARSE_OK;
+ nest = 0;
+ phase = 0;
+ num_stems = 0;
+ stack_top = 0;
+}
+
+/*
+ * Not just copying...
+ */
+long
+cs_copy_charstring (card8 *dst, long dstlen,
+ card8 *src, long srclen,
+ cff_index *gsubr, cff_index *subr,
+ double default_width, double nominal_width, cs_ginfo *ginfo)
+{
+ card8 *save = dst;
+
+ cs_parse_init();
+
+ width = 0.0;
+ have_width = 0;
+
+ /* expand call(g)subrs */
+ do_charstring(&dst, dst + dstlen, &src, src + srclen, gsubr, subr);
+
+ if (ginfo) {
+ ginfo->flags = 0; /* not used */
+ if (have_width) {
+ ginfo->wx = nominal_width + width;
+ } else {
+ ginfo->wx = default_width;
+ }
+ }
+
+ return (long)(dst - save);
+}