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; } }
void js_pushnumber(js_State *J, double v) { CHECKSTACK(1); STACK[TOP].type = JS_TNUMBER; STACK[TOP].u.number = v; ++TOP; }
void js_pushboolean(js_State *J, int v) { CHECKSTACK(1); STACK[TOP].type = JS_TBOOLEAN; STACK[TOP].u.boolean = !!v; ++TOP; }
void js_dup2(js_State *J) { CHECKSTACK(2); STACK[TOP] = STACK[TOP-2]; STACK[TOP+1] = STACK[TOP-1]; TOP += 2; }
void js_pushobject(js_State *J, js_Object *v) { CHECKSTACK(1); STACK[TOP].type = JS_TOBJECT; STACK[TOP].u.object = v; ++TOP; }
void js_pushliteral(js_State *J, const char *v) { CHECKSTACK(1); STACK[TOP].type = JS_TLITSTR; STACK[TOP].u.litstr = v; ++TOP; }
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; }
void js_pushnull(js_State *J) { CHECKSTACK(1); STACK[TOP].type = JS_TNULL; ++TOP; }
void js_pushundefined(js_State *J) { CHECKSTACK(1); STACK[TOP].type = JS_TUNDEFINED; ++TOP; }
void js_pushvalue(js_State *J, js_Value v) { CHECKSTACK(1); STACK[TOP] = v; ++TOP; }
void js_dup(js_State *J) { CHECKSTACK(1); STACK[TOP] = STACK[TOP-1]; ++TOP; }
void js_copy(js_State *J, int idx) { CHECKSTACK(1); STACK[TOP] = *stackidx(J, idx); ++TOP; }
void js_currentfunction(js_State *J) { CHECKSTACK(1); STACK[TOP] = STACK[BOT-1]; ++TOP; }
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; } } }
/* * 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; }
/* * 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; }