예제 #1
0
static void
do_callothersubr (t1_chardesc *cd)
{
  int argn, subrno;

  CHECKSTACK(2);
  subrno = (int) cs_arg_stack[--cs_stack_top];
  argn   = (int) cs_arg_stack[--cs_stack_top];

  CHECKSTACK(argn);
  if (ps_stack_top+argn > PS_ARG_STACK_MAX) {
    status = CS_PARSE_ERROR;
    return;
  }
  while (argn-- > 0)
    ps_arg_stack[ps_stack_top++] = cs_arg_stack[--cs_stack_top];

  switch (subrno) {
  case 0:  do_othersubr0(cd) ; break;
  case 1:  do_othersubr1()   ; break;
  case 2:  do_othersubr2(cd) ; break;
  case 3:  do_othersubr3(cd) ; break;
  case 12: do_othersubr12()  ; break;
  case 13: do_othersubr13(cd); break;
  default:
    ERROR("Unknown othersubr #%ld.", subrno);
    break;
  }
}
예제 #2
0
파일: jsrun.c 프로젝트: v09-software/mujs
void js_pushnumber(js_State *J, double v)
{
	CHECKSTACK(1);
	STACK[TOP].type = JS_TNUMBER;
	STACK[TOP].u.number = v;
	++TOP;
}
예제 #3
0
파일: jsrun.c 프로젝트: v09-software/mujs
void js_pushboolean(js_State *J, int v)
{
	CHECKSTACK(1);
	STACK[TOP].type = JS_TBOOLEAN;
	STACK[TOP].u.boolean = !!v;
	++TOP;
}
예제 #4
0
파일: jsrun.c 프로젝트: v09-software/mujs
void js_dup2(js_State *J)
{
	CHECKSTACK(2);
	STACK[TOP] = STACK[TOP-2];
	STACK[TOP+1] = STACK[TOP-1];
	TOP += 2;
}
예제 #5
0
파일: jsrun.c 프로젝트: v09-software/mujs
void js_pushobject(js_State *J, js_Object *v)
{
	CHECKSTACK(1);
	STACK[TOP].type = JS_TOBJECT;
	STACK[TOP].u.object = v;
	++TOP;
}
예제 #6
0
파일: jsrun.c 프로젝트: v09-software/mujs
void js_pushliteral(js_State *J, const char *v)
{
	CHECKSTACK(1);
	STACK[TOP].type = JS_TLITSTR;
	STACK[TOP].u.litstr = v;
	++TOP;
}
예제 #7
0
파일: jsrun.c 프로젝트: v09-software/mujs
void js_pushlstring(js_State *J, const char *v, unsigned int n)
{
	CHECKSTACK(1);
	if (n <= offsetof(js_Value, type)) {
		char *s = STACK[TOP].u.shrstr;
		while (n--) *s++ = *v++;
		*s = 0;
		STACK[TOP].type = JS_TSHRSTR;
	} else {
		STACK[TOP].type = JS_TMEMSTR;
		STACK[TOP].u.memstr = jsV_newmemstring(J, v, n);
	}
	++TOP;
}
예제 #8
0
파일: jsrun.c 프로젝트: v09-software/mujs
void js_pushnull(js_State *J)
{
	CHECKSTACK(1);
	STACK[TOP].type = JS_TNULL;
	++TOP;
}
예제 #9
0
파일: jsrun.c 프로젝트: v09-software/mujs
void js_pushundefined(js_State *J)
{
	CHECKSTACK(1);
	STACK[TOP].type = JS_TUNDEFINED;
	++TOP;
}
예제 #10
0
파일: jsrun.c 프로젝트: v09-software/mujs
void js_pushvalue(js_State *J, js_Value v)
{
	CHECKSTACK(1);
	STACK[TOP] = v;
	++TOP;
}
예제 #11
0
파일: jsrun.c 프로젝트: v09-software/mujs
void js_dup(js_State *J)
{
	CHECKSTACK(1);
	STACK[TOP] = STACK[TOP-1];
	++TOP;
}
예제 #12
0
파일: jsrun.c 프로젝트: v09-software/mujs
void js_copy(js_State *J, int idx)
{
	CHECKSTACK(1);
	STACK[TOP] = *stackidx(J, idx);
	++TOP;
}
예제 #13
0
파일: jsrun.c 프로젝트: v09-software/mujs
void js_currentfunction(js_State *J)
{
	CHECKSTACK(1);
	STACK[TOP] = STACK[BOT-1];
	++TOP;
}
예제 #14
0
파일: jsrun.c 프로젝트: v09-software/mujs
static void jsR_run(js_State *J, js_Function *F)
{
	js_Function **FT = F->funtab;
	double *NT = F->numtab;
	const char **ST = F->strtab;
	js_Instruction *pcstart = F->code;
	js_Instruction *pc = F->code;
	enum js_OpCode opcode;
	int offset;

	const char *str;
	js_Object *obj;
	double x, y;
	unsigned int ux, uy;
	int ix, iy, okay;
	int b;

	while (1) {
		if (J->gccounter > JS_GCLIMIT) {
			J->gccounter = 0;
			js_gc(J, 0);
		}

		opcode = *pc++;
		switch (opcode) {
		case OP_POP: js_pop(J, 1); break;
		case OP_DUP: js_dup(J); break;
		case OP_DUP2: js_dup2(J); break;
		case OP_ROT2: js_rot2(J); break;
		case OP_ROT3: js_rot3(J); break;
		case OP_ROT4: js_rot4(J); break;

		case OP_NUMBER_0: js_pushnumber(J, 0); break;
		case OP_NUMBER_1: js_pushnumber(J, 1); break;
		case OP_NUMBER_POS: js_pushnumber(J, *pc++); break;
		case OP_NUMBER_NEG: js_pushnumber(J, -(*pc++)); break;
		case OP_NUMBER: js_pushnumber(J, NT[*pc++]); break;
		case OP_STRING: js_pushliteral(J, ST[*pc++]); break;

		case OP_CLOSURE: js_newfunction(J, FT[*pc++], J->E); break;
		case OP_NEWOBJECT: js_newobject(J); break;
		case OP_NEWARRAY: js_newarray(J); break;
		case OP_NEWREGEXP: js_newregexp(J, ST[pc[0]], pc[1]); pc += 2; break;

		case OP_UNDEF: js_pushundefined(J); break;
		case OP_NULL: js_pushnull(J); break;
		case OP_TRUE: js_pushboolean(J, 1); break;
		case OP_FALSE: js_pushboolean(J, 0); break;

		case OP_THIS: js_copy(J, 0); break;
		case OP_GLOBAL: js_pushobject(J, J->G); break;
		case OP_CURRENT: js_currentfunction(J); break;

		case OP_INITLOCAL:
			STACK[BOT + *pc++] = STACK[--TOP];
			break;

		case OP_GETLOCAL:
			CHECKSTACK(1);
			STACK[TOP++] = STACK[BOT + *pc++];
			break;

		case OP_SETLOCAL:
			STACK[BOT + *pc++] = STACK[TOP-1];
			break;

		case OP_DELLOCAL:
			++pc;
			js_pushboolean(J, 0);
			break;

		case OP_INITVAR:
			js_initvar(J, ST[*pc++], -1);
			js_pop(J, 1);
			break;

		case OP_DEFVAR:
			js_defvar(J, ST[*pc++]);
			break;

		case OP_GETVAR:
			str = ST[*pc++];
			if (!js_hasvar(J, str))
				js_referenceerror(J, "'%s' is not defined", str);
			break;

		case OP_HASVAR:
			if (!js_hasvar(J, ST[*pc++]))
				js_pushundefined(J);
			break;

		case OP_SETVAR:
			js_setvar(J, ST[*pc++]);
			break;

		case OP_DELVAR:
			b = js_delvar(J, ST[*pc++]);
			js_pushboolean(J, b);
			break;

		case OP_IN:
			str = js_tostring(J, -2);
			if (!js_isobject(J, -1))
				js_typeerror(J, "operand to 'in' is not an object");
			b = js_hasproperty(J, -1, str);
			js_pop(J, 2 + b);
			js_pushboolean(J, b);
			break;

		case OP_INITPROP:
			obj = js_toobject(J, -3);
			str = js_tostring(J, -2);
			jsR_setproperty(J, obj, str, stackidx(J, -1));
			js_pop(J, 2);
			break;

		case OP_INITGETTER:
			obj = js_toobject(J, -3);
			str = js_tostring(J, -2);
			jsR_defproperty(J, obj, str, 0, NULL, jsR_tofunction(J, -1), NULL);
			js_pop(J, 2);
			break;

		case OP_INITSETTER:
			obj = js_toobject(J, -3);
			str = js_tostring(J, -2);
			jsR_defproperty(J, obj, str, 0, NULL, NULL, jsR_tofunction(J, -1));
			js_pop(J, 2);
			break;

		case OP_GETPROP:
			str = js_tostring(J, -1);
			obj = js_toobject(J, -2);
			jsR_getproperty(J, obj, str);
			js_rot3pop2(J);
			break;

		case OP_GETPROP_S:
			str = ST[*pc++];
			obj = js_toobject(J, -1);
			jsR_getproperty(J, obj, str);
			js_rot2pop1(J);
			break;

		case OP_SETPROP:
			str = js_tostring(J, -2);
			obj = js_toobject(J, -3);
			jsR_setproperty(J, obj, str, stackidx(J, -1));
			js_rot3pop2(J);
			break;

		case OP_SETPROP_S:
			str = ST[*pc++];
			obj = js_toobject(J, -2);
			jsR_setproperty(J, obj, str, stackidx(J, -1));
			js_rot2pop1(J);
			break;

		case OP_DELPROP:
			str = js_tostring(J, -1);
			obj = js_toobject(J, -2);
			b = jsR_delproperty(J, obj, str);
			js_pop(J, 2);
			js_pushboolean(J, b);
			break;

		case OP_DELPROP_S:
			str = ST[*pc++];
			obj = js_toobject(J, -1);
			b = jsR_delproperty(J, obj, str);
			js_pop(J, 1);
			js_pushboolean(J, b);
			break;

		case OP_ITERATOR:
			if (!js_isundefined(J, -1) && !js_isnull(J, -1)) {
				obj = jsV_newiterator(J, js_toobject(J, -1), 0);
				js_pop(J, 1);
				js_pushobject(J, obj);
			}
			break;

		case OP_NEXTITER:
			obj = js_toobject(J, -1);
			str = jsV_nextiterator(J, obj);
			if (str) {
				js_pushliteral(J, str);
				js_pushboolean(J, 1);
			} else {
				js_pop(J, 1);
				js_pushboolean(J, 0);
			}
			break;

		/* Function calls */

		case OP_EVAL:
			js_eval(J);
			break;

		case OP_CALL:
			js_call(J, *pc++);
			break;

		case OP_NEW:
			js_construct(J, *pc++);
			break;

		/* Unary operators */

		case OP_TYPEOF:
			str = js_typeof(J, -1);
			js_pop(J, 1);
			js_pushliteral(J, str);
			break;

		case OP_POS:
			x = js_tonumber(J, -1);
			js_pop(J, 1);
			js_pushnumber(J, x);
			break;

		case OP_NEG:
			x = js_tonumber(J, -1);
			js_pop(J, 1);
			js_pushnumber(J, -x);
			break;

		case OP_BITNOT:
			ix = js_toint32(J, -1);
			js_pop(J, 1);
			js_pushnumber(J, ~ix);
			break;

		case OP_LOGNOT:
			b = js_toboolean(J, -1);
			js_pop(J, 1);
			js_pushboolean(J, !b);
			break;

		case OP_INC:
			x = js_tonumber(J, -1);
			js_pop(J, 1);
			js_pushnumber(J, x + 1);
			break;

		case OP_DEC:
			x = js_tonumber(J, -1);
			js_pop(J, 1);
			js_pushnumber(J, x - 1);
			break;

		case OP_POSTINC:
			x = js_tonumber(J, -1);
			js_pop(J, 1);
			js_pushnumber(J, x + 1);
			js_pushnumber(J, x);
			break;

		case OP_POSTDEC:
			x = js_tonumber(J, -1);
			js_pop(J, 1);
			js_pushnumber(J, x - 1);
			js_pushnumber(J, x);
			break;

		/* Multiplicative operators */

		case OP_MUL:
			x = js_tonumber(J, -2);
			y = js_tonumber(J, -1);
			js_pop(J, 2);
			js_pushnumber(J, x * y);
			break;

		case OP_DIV:
			x = js_tonumber(J, -2);
			y = js_tonumber(J, -1);
			js_pop(J, 2);
			js_pushnumber(J, x / y);
			break;

		case OP_MOD:
			x = js_tonumber(J, -2);
			y = js_tonumber(J, -1);
			js_pop(J, 2);
			js_pushnumber(J, fmod(x, y));
			break;

		/* Additive operators */

		case OP_ADD:
			js_concat(J);
			break;

		case OP_SUB:
			x = js_tonumber(J, -2);
			y = js_tonumber(J, -1);
			js_pop(J, 2);
			js_pushnumber(J, x - y);
			break;

		/* Shift operators */

		case OP_SHL:
			ix = js_toint32(J, -2);
			uy = js_touint32(J, -1);
			js_pop(J, 2);
			js_pushnumber(J, ix << (uy & 0x1F));
			break;

		case OP_SHR:
			ix = js_toint32(J, -2);
			uy = js_touint32(J, -1);
			js_pop(J, 2);
			js_pushnumber(J, ix >> (uy & 0x1F));
			break;

		case OP_USHR:
			ux = js_touint32(J, -2);
			uy = js_touint32(J, -1);
			js_pop(J, 2);
			js_pushnumber(J, ux >> (uy & 0x1F));
			break;

		/* Relational operators */

		case OP_LT: b = js_compare(J, &okay); js_pop(J, 2); js_pushboolean(J, okay && b < 0); break;
		case OP_GT: b = js_compare(J, &okay); js_pop(J, 2); js_pushboolean(J, okay && b > 0); break;
		case OP_LE: b = js_compare(J, &okay); js_pop(J, 2); js_pushboolean(J, okay && b <= 0); break;
		case OP_GE: b = js_compare(J, &okay); js_pop(J, 2); js_pushboolean(J, okay && b >= 0); break;

		case OP_INSTANCEOF:
			b = js_instanceof(J);
			js_pop(J, 2);
			js_pushboolean(J, b);
			break;

		/* Equality */

		case OP_EQ: b = js_equal(J); js_pop(J, 2); js_pushboolean(J, b); break;
		case OP_NE: b = js_equal(J); js_pop(J, 2); js_pushboolean(J, !b); break;
		case OP_STRICTEQ: b = js_strictequal(J); js_pop(J, 2); js_pushboolean(J, b); break;
		case OP_STRICTNE: b = js_strictequal(J); js_pop(J, 2); js_pushboolean(J, !b); break;

		case OP_JCASE:
			offset = *pc++;
			b = js_strictequal(J);
			if (b) {
				js_pop(J, 2);
				pc = pcstart + offset;
			} else {
				js_pop(J, 1);
			}
			break;

		/* Binary bitwise operators */

		case OP_BITAND:
			ix = js_toint32(J, -2);
			iy = js_toint32(J, -1);
			js_pop(J, 2);
			js_pushnumber(J, ix & iy);
			break;

		case OP_BITXOR:
			ix = js_toint32(J, -2);
			iy = js_toint32(J, -1);
			js_pop(J, 2);
			js_pushnumber(J, ix ^ iy);
			break;

		case OP_BITOR:
			ix = js_toint32(J, -2);
			iy = js_toint32(J, -1);
			js_pop(J, 2);
			js_pushnumber(J, ix | iy);
			break;

		/* Try and Catch */

		case OP_THROW:
			js_throw(J);

		case OP_TRY:
			offset = *pc++;
			if (js_trypc(J, pc)) {
				pc = J->trybuf[J->trytop].pc;
			} else {
				pc = pcstart + offset;
			}
			break;

		case OP_ENDTRY:
			js_endtry(J);
			break;

		case OP_CATCH:
			str = ST[*pc++];
			obj = jsV_newobject(J, JS_COBJECT, NULL);
			js_pushobject(J, obj);
			js_rot2(J);
			js_setproperty(J, -2, str);
			J->E = jsR_newenvironment(J, obj, J->E);
			js_pop(J, 1);
			break;

		case OP_ENDCATCH:
			J->E = J->E->outer;
			break;

		/* With */

		case OP_WITH:
			obj = js_toobject(J, -1);
			J->E = jsR_newenvironment(J, obj, J->E);
			js_pop(J, 1);
			break;

		case OP_ENDWITH:
			J->E = J->E->outer;
			break;

		/* Branching */

		case OP_DEBUGGER:
			js_trap(J, (int)(pc - pcstart) - 1);
			break;

		case OP_JUMP:
			pc = pcstart + *pc;
			break;

		case OP_JTRUE:
			offset = *pc++;
			b = js_toboolean(J, -1);
			js_pop(J, 1);
			if (b)
				pc = pcstart + offset;
			break;

		case OP_JFALSE:
			offset = *pc++;
			b = js_toboolean(J, -1);
			js_pop(J, 1);
			if (!b)
				pc = pcstart + offset;
			break;

		case OP_RETURN:
			return;

		case OP_LINE:
			J->trace[J->tracetop].line = *pc++;
			break;
		}
	}
}
예제 #15
0
/*
 * Double byte operators:
 */
static void
do_operator2 (t1_chardesc *cd, card8 **data, card8 *endptr)
{
  card8 op;

  *data += 1;

  SRC_NEED(endptr, *data + 1);

  op = **data;
  *data += 1;

  switch(op) {
  case cs_sbw:
    CHECKSTACK(4);
    cd->sbw.wy  = cs_arg_stack[--cs_stack_top];
    cd->sbw.wx  = cs_arg_stack[--cs_stack_top];
    cd->sbw.sby = cs_arg_stack[--cs_stack_top];
    cd->sbw.sbx = cs_arg_stack[--cs_stack_top];
    CLEARSTACK();
    break;
  case cs_hstem3:
  case cs_vstem3:
    /*
     * TODO:
     *  The counter control can be used for hstem3 and vstem3
     *  operator if LanguageGroup is not equal to 1.
     */
    CHECKSTACK(6);
    {
      int i;
      for (i = 2; i >= 0; i--) {
        int stem_id;
        stem_id = add_stem(cd,
                           cs_arg_stack[cs_stack_top-2*i-2],
                           cs_arg_stack[cs_stack_top-2*i-1],
                           ((op == cs_hstem3) ? HSTEM : VSTEM));
        if (stem_id < 0) {
          WARN("Too many hints...");
          status = CS_PARSE_ERROR;
          return;
        }
        /* Put stem_id onto the stack... */
        cs_arg_stack[cs_stack_top++] = stem_id;
        ADD_PATH(cd, CS_HINT_DECL, 1);
        cs_stack_top--;
      }
    }
    CLEARSTACK();
    break;
  case cs_setcurrentpoint:
    CHECKSTACK(2);
    /* noop */
    CLEARSTACK();
    break;
    /* all operator above are stack-clearing */
  case cs_pop:
    /*
     * Transfer a operand from PS interpreter operand stack to BuildChar
     * operand stack.
     */
    if (ps_stack_top < 1) {
      status = CS_PARSE_ERROR;
      return;
    }
    LIMITCHECK(1);
    cs_arg_stack[cs_stack_top++] = ps_arg_stack[--ps_stack_top];
    break;
  case cs_dotsection:
#if 0
    /*
     * If the hint replacement feature is used in the font, the
     * "dotsection" operator exist only for compatibility to older
     * (more than 10 years old) Type 1 font rasterizer which can't
     * perform hint replacement. In this case, we silently ignore
     * the "dotsection" operator.
     *
     * The following code will wrongly warn about "dotsection" when
     * the charstring only contains dot (e.g., "bullet") where the
     * hint replacement is not necessary.
     *
     * Adobe ATM renderers always treat this operator as a no-op.
     * (See, Adobe Technical Note #5177, Appendix C)
     */
    if (!(cd->flags & T1_CS_FLAG_USE_HINTMASK)) {
      if (dpx_conf.verbose_level > 1)
        WARN("Obsolete Type 1 charstring operator \"dotsection\" not supported.");
    }
#endif
    /* noop */
    break;
  case cs_div: /* TODO: check overflow */
    CHECKSTACK(2);
    cs_arg_stack[cs_stack_top-2] /= cs_arg_stack[cs_stack_top-1];
    cs_stack_top--;
    break;
  case cs_callothersubr:
    do_callothersubr(cd);
    break;
  case cs_seac:
    CHECKSTACK(5);
    cd->flags |= T1_CS_FLAG_USE_SEAC;
    cd->seac.achar = (card8) cs_arg_stack[--cs_stack_top];
    cd->seac.bchar = (card8) cs_arg_stack[--cs_stack_top];
    cd->seac.ady   = cs_arg_stack[--cs_stack_top];
    cd->seac.adx   = cs_arg_stack[--cs_stack_top];
    /* We must compensate the difference of the glyph origin. */
    cd->seac.ady += cd->sbw.sby;
    cd->seac.adx += cd->sbw.sbx - cs_arg_stack[--cs_stack_top];
    CLEARSTACK();
    break;
  default:
    /* no-op ? */
    WARN("Unknown charstring operator: 0x0c%02x", op);
    status = CS_PARSE_ERROR;
    break;
  }

  return;
}
예제 #16
0
/*
 * Single byte operators:
 */
static void
do_operator1 (t1_chardesc *cd, card8 **data)
{
  card8 op = **data;

  *data += 1;

  switch (op) {
  case cs_closepath:
    /*
     * From T1 spec.:
     *  Note that, unlike the closepath command in the PostScript language,
     *  this command does not reposition the current point. Any subsequent
     *  rmoveto must be relative to the current point in force before the
     *  Type 1 font format closepath command was given.
     */
    /* noop */
    CLEARSTACK();
    break;
  case cs_hsbw:
    CHECKSTACK(2);
    cd->sbw.wx  = cs_arg_stack[--cs_stack_top];
    cd->sbw.wy  = 0;
    cd->sbw.sbx = cs_arg_stack[--cs_stack_top];
    cd->sbw.sby = 0;
    CLEARSTACK();
    /* hsbw does NOT set currentpoint. */
    break;
  case cs_hstem:
  case cs_vstem:
    CHECKSTACK(2);
    {
      int stem_id;
      stem_id = add_stem(cd,
                         cs_arg_stack[cs_stack_top-2],
                         cs_arg_stack[cs_stack_top-1],
                         ((op == cs_hstem) ? HSTEM : VSTEM));
      if (stem_id < 0) {
        WARN("Too many hints...");
        status = CS_PARSE_ERROR;
        return;
      }
      /* Put stem_id onto the stack... */
      cs_arg_stack[cs_stack_top++] = stem_id;
      ADD_PATH(cd, CS_HINT_DECL, 1);
    }
    CLEARSTACK();
    break;
  case cs_rmoveto:
    /*
     * Reference point is (0, 0) in Type 2 charstring.
     */
    CHECKSTACK(2);
    {
      if (phase < T1_CS_PHASE_PATH) {
        cs_arg_stack[cs_stack_top-2] += cd->sbw.sbx;
        cs_arg_stack[cs_stack_top-1] += cd->sbw.sby;
      }
      ADD_PATH(cd, op, 2);
    }
    CLEARSTACK();
    break;
  case cs_hmoveto:
  case cs_vmoveto:
    CHECKSTACK(1);
    {
      int argn = 1;
      if (phase < T1_CS_PHASE_PATH) {
        /*
         * The reference point for the first moveto operator is diferrent
         * between Type 1 charstring and Type 2 charstring. We compensate it.
         */
        if (op == cs_hmoveto) {
          cs_arg_stack[cs_stack_top-1] += cd->sbw.sbx;
          if (cd->sbw.sby != 0.0) {
            cs_arg_stack[cs_stack_top++] = cd->sbw.sby;
            argn = 2;
            op = cs_rmoveto;
          }
        } else {
          cs_arg_stack[cs_stack_top-1] += cd->sbw.sby;
          if (cd->sbw.sbx != 0.0) {
            cs_arg_stack[cs_stack_top]   = cs_arg_stack[cs_stack_top-1];
            cs_arg_stack[cs_stack_top-1] = cd->sbw.sbx;
            cs_stack_top++;
            argn = 2;
            op = cs_rmoveto;
          }
        }
      }
      ADD_PATH(cd, op, argn);
    }
    CLEARSTACK();
    break;
  case cs_endchar:
    status = CS_CHAR_END;
    CLEARSTACK();
    break;
  /* above oprators are candidate for first stack-clearing operator */
  case cs_rlineto:
    CHECKSTACK(2);
    ADD_PATH(cd, op, 2);
    CLEARSTACK();
    break;
  case cs_hlineto:
  case cs_vlineto:
    CHECKSTACK(1);
    ADD_PATH(cd, op, 1);
    CLEARSTACK();
    break;
  case cs_rrcurveto:
    CHECKSTACK(6);
    ADD_PATH(cd, op, 6);
    CLEARSTACK();
    break;
  case cs_vhcurveto:
  case cs_hvcurveto:
    CHECKSTACK(4);
    ADD_PATH(cd, op, 4);
    CLEARSTACK();
    break;
    /* all operotors above are stack-clearing operator */
    /* no output */
  case cs_return:
    break;
  case cs_callsubr:
    ERROR("Unexpected callsubr.");
    break;
  default:
    /* no-op ? */
    WARN("Unknown charstring operator: 0x%02x", op);
    status = CS_PARSE_ERROR;
    break;
  }

  return;
}