13ff48bf5SDavid du Colombier /* Copyright (C) 1999, 2000 Aladdin Enterprises. All rights reserved.
27dd7cddfSDavid du Colombier
3*593dc095SDavid du Colombier This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier implied.
57dd7cddfSDavid du Colombier
6*593dc095SDavid du Colombier This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier
10*593dc095SDavid du Colombier For more information about licensing, please refer to
11*593dc095SDavid du Colombier http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier San Rafael, CA 94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier
17*593dc095SDavid du Colombier /* $Id: zfunc4.c,v 1.12 2004/08/04 19:36:13 stefan Exp $ */
187dd7cddfSDavid du Colombier /* PostScript language support for FunctionType 4 (PS Calculator) Functions */
197dd7cddfSDavid du Colombier #include "memory_.h"
207dd7cddfSDavid du Colombier #include "ghost.h"
217dd7cddfSDavid du Colombier #include "oper.h"
227dd7cddfSDavid du Colombier #include "opextern.h"
237dd7cddfSDavid du Colombier #include "gsfunc.h"
243ff48bf5SDavid du Colombier #include "gsfunc4.h"
253ff48bf5SDavid du Colombier #include "gsutil.h"
267dd7cddfSDavid du Colombier #include "idict.h"
277dd7cddfSDavid du Colombier #include "ifunc.h"
283ff48bf5SDavid du Colombier #include "iname.h"
293ff48bf5SDavid du Colombier #include "dstack.h"
30*593dc095SDavid du Colombier #include "ialloc.h"
317dd7cddfSDavid du Colombier /*
323ff48bf5SDavid du Colombier * FunctionType 4 functions are not defined in the PostScript language. We
333ff48bf5SDavid du Colombier * provide support for them because they are needed for PDF 1.3. In
343ff48bf5SDavid du Colombier * addition to the standard FunctionType, Domain, and Range keys, they have
353ff48bf5SDavid du Colombier * a Function key whose value is a procedure in a restricted subset of the
363ff48bf5SDavid du Colombier * PostScript language. Specifically, the procedure must (recursively)
373ff48bf5SDavid du Colombier * contain only integer, real, Boolean, and procedure constants (only as
383ff48bf5SDavid du Colombier * literal operands of if and and ifelse), and operators chosen from the set
393ff48bf5SDavid du Colombier * given below. Note that names other than true and false are not allowed:
403ff48bf5SDavid du Colombier * the procedure must be 'bound'.
417dd7cddfSDavid du Colombier *
427dd7cddfSDavid du Colombier * The following list is taken directly from the PDF 1.3 documentation.
437dd7cddfSDavid du Colombier */
44*593dc095SDavid du Colombier #define XOP(zfn) int zfn(i_ctx_t *)
457dd7cddfSDavid du Colombier XOP(zabs); XOP(zand); XOP(zatan); XOP(zbitshift);
467dd7cddfSDavid du Colombier XOP(zceiling); XOP(zcos); XOP(zcvi); XOP(zcvr);
477dd7cddfSDavid du Colombier XOP(zdiv); XOP(zexp); XOP(zfloor); XOP(zidiv);
487dd7cddfSDavid du Colombier XOP(zln); XOP(zlog); XOP(zmod); XOP(zmul);
497dd7cddfSDavid du Colombier XOP(zneg); XOP(znot); XOP(zor); XOP(zround);
507dd7cddfSDavid du Colombier XOP(zsin); XOP(zsqrt); XOP(ztruncate); XOP(zxor);
517dd7cddfSDavid du Colombier XOP(zeq); XOP(zge); XOP(zgt); XOP(zle); XOP(zlt); XOP(zne);
523ff48bf5SDavid du Colombier XOP(z2copy);
537dd7cddfSDavid du Colombier #undef XOP
543ff48bf5SDavid du Colombier typedef struct calc_op_s {
553ff48bf5SDavid du Colombier op_proc_t proc;
563ff48bf5SDavid du Colombier gs_PtCr_opcode_t opcode;
573ff48bf5SDavid du Colombier } calc_op_t;
583ff48bf5SDavid du Colombier static const calc_op_t calc_ops[] = {
597dd7cddfSDavid du Colombier
607dd7cddfSDavid du Colombier /* Arithmetic operators */
617dd7cddfSDavid du Colombier
623ff48bf5SDavid du Colombier {zabs, PtCr_abs},
633ff48bf5SDavid du Colombier {zadd, PtCr_add},
643ff48bf5SDavid du Colombier {zand, PtCr_and},
653ff48bf5SDavid du Colombier {zatan, PtCr_atan},
663ff48bf5SDavid du Colombier {zbitshift, PtCr_bitshift},
673ff48bf5SDavid du Colombier {zceiling, PtCr_ceiling},
683ff48bf5SDavid du Colombier {zcos, PtCr_cos},
693ff48bf5SDavid du Colombier {zcvi, PtCr_cvi},
703ff48bf5SDavid du Colombier {zcvr, PtCr_cvr},
713ff48bf5SDavid du Colombier {zdiv, PtCr_div},
723ff48bf5SDavid du Colombier {zexp, PtCr_exp},
733ff48bf5SDavid du Colombier {zfloor, PtCr_floor},
743ff48bf5SDavid du Colombier {zidiv, PtCr_idiv},
753ff48bf5SDavid du Colombier {zln, PtCr_ln},
763ff48bf5SDavid du Colombier {zlog, PtCr_log},
773ff48bf5SDavid du Colombier {zmod, PtCr_mod},
783ff48bf5SDavid du Colombier {zmul, PtCr_mul},
793ff48bf5SDavid du Colombier {zneg, PtCr_neg},
803ff48bf5SDavid du Colombier {znot, PtCr_not},
813ff48bf5SDavid du Colombier {zor, PtCr_or},
823ff48bf5SDavid du Colombier {zround, PtCr_round},
833ff48bf5SDavid du Colombier {zsin, PtCr_sin},
843ff48bf5SDavid du Colombier {zsqrt, PtCr_sqrt},
853ff48bf5SDavid du Colombier {zsub, PtCr_sub},
863ff48bf5SDavid du Colombier {ztruncate, PtCr_truncate},
873ff48bf5SDavid du Colombier {zxor, PtCr_xor},
883ff48bf5SDavid du Colombier
893ff48bf5SDavid du Colombier /* Comparison operators */
903ff48bf5SDavid du Colombier
913ff48bf5SDavid du Colombier {zeq, PtCr_eq},
923ff48bf5SDavid du Colombier {zge, PtCr_ge},
933ff48bf5SDavid du Colombier {zgt, PtCr_gt},
943ff48bf5SDavid du Colombier {zle, PtCr_le},
953ff48bf5SDavid du Colombier {zlt, PtCr_lt},
963ff48bf5SDavid du Colombier {zne, PtCr_ne},
977dd7cddfSDavid du Colombier
987dd7cddfSDavid du Colombier /* Stack operators */
993ff48bf5SDavid du Colombier
1003ff48bf5SDavid du Colombier {zcopy, PtCr_copy},
1013ff48bf5SDavid du Colombier {z2copy, PtCr_copy},
1023ff48bf5SDavid du Colombier {zdup, PtCr_dup},
1033ff48bf5SDavid du Colombier {zexch, PtCr_exch},
1043ff48bf5SDavid du Colombier {zindex, PtCr_index},
1053ff48bf5SDavid du Colombier {zpop, PtCr_pop},
1063ff48bf5SDavid du Colombier {zroll, PtCr_roll}
1073ff48bf5SDavid du Colombier
1083ff48bf5SDavid du Colombier /* Special operators */
1093ff48bf5SDavid du Colombier
1103ff48bf5SDavid du Colombier /*{zif, PtCr_if},*/
1113ff48bf5SDavid du Colombier /*{zifelse, PtCr_ifelse},*/
1123ff48bf5SDavid du Colombier /*{ztrue, PtCr_true},*/
1133ff48bf5SDavid du Colombier /*{zfalse, PtCr_false}*/
1147dd7cddfSDavid du Colombier };
1157dd7cddfSDavid du Colombier
1163ff48bf5SDavid du Colombier /* Fix up an if or ifelse forward reference. */
1173ff48bf5SDavid du Colombier private void
psc_fixup(byte * p,byte * to)1183ff48bf5SDavid du Colombier psc_fixup(byte *p, byte *to)
1199a747e4fSDavid du Colombier {
1203ff48bf5SDavid du Colombier int skip = to - (p + 3);
1219a747e4fSDavid du Colombier
1223ff48bf5SDavid du Colombier p[1] = (byte)(skip >> 8);
1233ff48bf5SDavid du Colombier p[2] = (byte)skip;
1247dd7cddfSDavid du Colombier }
1257dd7cddfSDavid du Colombier
1267dd7cddfSDavid du Colombier /*
1273ff48bf5SDavid du Colombier * Check a calculator function for validity, optionally storing its encoded
1283ff48bf5SDavid du Colombier * representation and add the size of the encoded representation to *psize.
1293ff48bf5SDavid du Colombier * Note that we arbitrarily limit the depth of procedure nesting. pref is
1303ff48bf5SDavid du Colombier * known to be a procedure.
1317dd7cddfSDavid du Colombier */
1323ff48bf5SDavid du Colombier #define MAX_PSC_FUNCTION_NESTING 10
1337dd7cddfSDavid du Colombier private int
check_psc_function(i_ctx_t * i_ctx_p,const ref * pref,int depth,byte * ops,int * psize)1343ff48bf5SDavid du Colombier check_psc_function(i_ctx_t *i_ctx_p, const ref *pref, int depth, byte *ops, int *psize)
1357dd7cddfSDavid du Colombier {
1367dd7cddfSDavid du Colombier long i;
1373ff48bf5SDavid du Colombier uint size = r_size(pref);
1387dd7cddfSDavid du Colombier
1393ff48bf5SDavid du Colombier for (i = 0; i < size; ++i) {
1403ff48bf5SDavid du Colombier byte no_ops[1 + max(sizeof(int), sizeof(float))];
1413ff48bf5SDavid du Colombier byte *p = (ops ? ops + *psize : no_ops);
1423ff48bf5SDavid du Colombier ref elt, elt2, elt3;
1433ff48bf5SDavid du Colombier ref * delp;
1449a747e4fSDavid du Colombier int code;
1459a747e4fSDavid du Colombier
146*593dc095SDavid du Colombier array_get(imemory, pref, i, &elt);
1473ff48bf5SDavid du Colombier switch (r_btype(&elt)) {
1483ff48bf5SDavid du Colombier case t_integer: {
1493ff48bf5SDavid du Colombier int i = elt.value.intval;
1503ff48bf5SDavid du Colombier
1513ff48bf5SDavid du Colombier #if ARCH_SIZEOF_INT < ARCH_SIZEOF_LONG
1523ff48bf5SDavid du Colombier if (i != elt.value.intval) /* check for truncation */
1533ff48bf5SDavid du Colombier return_error(e_rangecheck);
1543ff48bf5SDavid du Colombier #endif
1553ff48bf5SDavid du Colombier if (i == (byte)i) {
1563ff48bf5SDavid du Colombier *p = PtCr_byte;
1573ff48bf5SDavid du Colombier p[1] = (byte)i;
1583ff48bf5SDavid du Colombier *psize += 2;
1593ff48bf5SDavid du Colombier } else {
1603ff48bf5SDavid du Colombier *p = PtCr_int;
1613ff48bf5SDavid du Colombier memcpy(p + 1, &i, sizeof(i));
1623ff48bf5SDavid du Colombier *psize += 1 + sizeof(int);
1633ff48bf5SDavid du Colombier }
1643ff48bf5SDavid du Colombier break;
1653ff48bf5SDavid du Colombier }
1663ff48bf5SDavid du Colombier case t_real: {
1673ff48bf5SDavid du Colombier float f = elt.value.realval;
1683ff48bf5SDavid du Colombier
1693ff48bf5SDavid du Colombier *p = PtCr_float;
1703ff48bf5SDavid du Colombier memcpy(p + 1, &f, sizeof(f));
1713ff48bf5SDavid du Colombier *psize += 1 + sizeof(float);
1723ff48bf5SDavid du Colombier break;
1733ff48bf5SDavid du Colombier }
1743ff48bf5SDavid du Colombier case t_boolean:
1753ff48bf5SDavid du Colombier *p = (elt.value.boolval ? PtCr_true : PtCr_false);
1763ff48bf5SDavid du Colombier ++*psize;
1773ff48bf5SDavid du Colombier break;
1783ff48bf5SDavid du Colombier case t_name:
1793ff48bf5SDavid du Colombier if (!r_has_attr(&elt, a_executable))
1803ff48bf5SDavid du Colombier return_error(e_rangecheck);
181*593dc095SDavid du Colombier name_string_ref(imemory, &elt, &elt);
1823ff48bf5SDavid du Colombier if (!bytes_compare(elt.value.bytes, r_size(&elt),
1833ff48bf5SDavid du Colombier (const byte *)"true", 4)) {
1843ff48bf5SDavid du Colombier *p = PtCr_true;
1853ff48bf5SDavid du Colombier ++*psize;
1863ff48bf5SDavid du Colombier break;
1873ff48bf5SDavid du Colombier }
1883ff48bf5SDavid du Colombier if (!bytes_compare(elt.value.bytes, r_size(&elt),
1893ff48bf5SDavid du Colombier (const byte *)"false", 5)) {
1903ff48bf5SDavid du Colombier *p = PtCr_false;
1913ff48bf5SDavid du Colombier ++*psize;
1923ff48bf5SDavid du Colombier break;
1933ff48bf5SDavid du Colombier }
1943ff48bf5SDavid du Colombier /* Check if the name is a valid operator in systemdict */
1953ff48bf5SDavid du Colombier if (dict_find(systemdict, &elt, &delp) <= 0)
1963ff48bf5SDavid du Colombier return_error(e_undefined);
1973ff48bf5SDavid du Colombier if (r_btype(delp) != t_operator)
1983ff48bf5SDavid du Colombier return_error(e_typecheck);
1993ff48bf5SDavid du Colombier if (!r_has_attr(delp, a_executable))
2003ff48bf5SDavid du Colombier return_error(e_rangecheck);
2013ff48bf5SDavid du Colombier elt = *delp;
2023ff48bf5SDavid du Colombier /* Fall into the operator case */
2033ff48bf5SDavid du Colombier case t_operator: {
2043ff48bf5SDavid du Colombier int j;
2053ff48bf5SDavid du Colombier
2063ff48bf5SDavid du Colombier for (j = 0; j < countof(calc_ops); ++j)
2073ff48bf5SDavid du Colombier if (elt.value.opproc == calc_ops[j].proc) {
2083ff48bf5SDavid du Colombier *p = calc_ops[j].opcode;
2093ff48bf5SDavid du Colombier ++*psize;
2103ff48bf5SDavid du Colombier goto next;
2113ff48bf5SDavid du Colombier }
2123ff48bf5SDavid du Colombier return_error(e_rangecheck);
2133ff48bf5SDavid du Colombier }
2143ff48bf5SDavid du Colombier default: {
2153ff48bf5SDavid du Colombier if (!r_is_proc(&elt))
2163ff48bf5SDavid du Colombier return_error(e_typecheck);
2173ff48bf5SDavid du Colombier if (depth == MAX_PSC_FUNCTION_NESTING)
2183ff48bf5SDavid du Colombier return_error(e_limitcheck);
219*593dc095SDavid du Colombier if ((code = array_get(imemory, pref, ++i, &elt2)) < 0)
2203ff48bf5SDavid du Colombier return code;
2213ff48bf5SDavid du Colombier *psize += 3;
2223ff48bf5SDavid du Colombier code = check_psc_function(i_ctx_p, &elt, depth + 1, ops, psize);
2237dd7cddfSDavid du Colombier if (code < 0)
2247dd7cddfSDavid du Colombier return code;
2253ff48bf5SDavid du Colombier /* Check for {proc} if | {proc1} {proc2} ifelse */
2263ff48bf5SDavid du Colombier #define R_IS_OPER(pref, proc)\
2273ff48bf5SDavid du Colombier (r_btype(pref) == t_operator && r_has_attr(pref, a_executable) &&\
2283ff48bf5SDavid du Colombier (pref)->value.opproc == proc)
2293ff48bf5SDavid du Colombier if (R_IS_OPER(&elt2, zif)) {
2303ff48bf5SDavid du Colombier if (ops) {
2313ff48bf5SDavid du Colombier *p = PtCr_if;
2323ff48bf5SDavid du Colombier psc_fixup(p, ops + *psize);
2333ff48bf5SDavid du Colombier }
2343ff48bf5SDavid du Colombier } else if (!r_is_proc(&elt2))
2353ff48bf5SDavid du Colombier return_error(e_rangecheck);
236*593dc095SDavid du Colombier else if ((code == array_get(imemory, pref, ++i, &elt3)) < 0)
2373ff48bf5SDavid du Colombier return code;
2383ff48bf5SDavid du Colombier else if (R_IS_OPER(&elt3, zifelse)) {
2393ff48bf5SDavid du Colombier if (ops) {
2403ff48bf5SDavid du Colombier *p = PtCr_if;
2413ff48bf5SDavid du Colombier psc_fixup(p, ops + *psize + 3);
2423ff48bf5SDavid du Colombier p = ops + *psize;
2433ff48bf5SDavid du Colombier *p = PtCr_else;
2443ff48bf5SDavid du Colombier }
2453ff48bf5SDavid du Colombier *psize += 3;
2463ff48bf5SDavid du Colombier code = check_psc_function(i_ctx_p, &elt2, depth + 1, ops, psize);
2473ff48bf5SDavid du Colombier if (code < 0)
2483ff48bf5SDavid du Colombier return code;
2493ff48bf5SDavid du Colombier if (ops)
2503ff48bf5SDavid du Colombier psc_fixup(p, ops + *psize);
2513ff48bf5SDavid du Colombier } else
2523ff48bf5SDavid du Colombier return_error(e_rangecheck);
2533ff48bf5SDavid du Colombier #undef R_IS_OPER
2543ff48bf5SDavid du Colombier }
2553ff48bf5SDavid du Colombier }
2563ff48bf5SDavid du Colombier next:
2573ff48bf5SDavid du Colombier DO_NOTHING;
2587dd7cddfSDavid du Colombier }
2597dd7cddfSDavid du Colombier return 0;
2607dd7cddfSDavid du Colombier }
2617dd7cddfSDavid du Colombier #undef MAX_PSC_FUNCTION_NESTING
2627dd7cddfSDavid du Colombier
2637dd7cddfSDavid du Colombier /* Check prototype */
2647dd7cddfSDavid du Colombier build_function_proc(gs_build_function_4);
2657dd7cddfSDavid du Colombier
2667dd7cddfSDavid du Colombier /* Finish building a FunctionType 4 (PostScript Calculator) function. */
2677dd7cddfSDavid du Colombier int
gs_build_function_4(i_ctx_t * i_ctx_p,const ref * op,const gs_function_params_t * mnDR,int depth,gs_function_t ** ppfn,gs_memory_t * mem)2683ff48bf5SDavid du Colombier gs_build_function_4(i_ctx_t *i_ctx_p, const ref *op, const gs_function_params_t * mnDR,
2697dd7cddfSDavid du Colombier int depth, gs_function_t ** ppfn, gs_memory_t *mem)
2707dd7cddfSDavid du Colombier {
2713ff48bf5SDavid du Colombier gs_function_PtCr_params_t params;
2727dd7cddfSDavid du Colombier ref *proc;
2733ff48bf5SDavid du Colombier int code;
2743ff48bf5SDavid du Colombier byte *ops;
2753ff48bf5SDavid du Colombier int size;
2767dd7cddfSDavid du Colombier
2777dd7cddfSDavid du Colombier *(gs_function_params_t *)¶ms = *mnDR;
2783ff48bf5SDavid du Colombier params.ops.data = 0; /* in case of failure */
2793ff48bf5SDavid du Colombier params.ops.size = 0; /* ditto */
2803ff48bf5SDavid du Colombier if (dict_find_string(op, "Function", &proc) <= 0) {
2813ff48bf5SDavid du Colombier code = gs_note_error(e_rangecheck);
2827dd7cddfSDavid du Colombier goto fail;
2833ff48bf5SDavid du Colombier }
2843ff48bf5SDavid du Colombier if (!r_is_proc(proc)) {
2853ff48bf5SDavid du Colombier code = gs_note_error(e_typecheck);
2863ff48bf5SDavid du Colombier goto fail;
2873ff48bf5SDavid du Colombier }
2883ff48bf5SDavid du Colombier size = 0;
2893ff48bf5SDavid du Colombier code = check_psc_function(i_ctx_p, proc, 0, NULL, &size);
2907dd7cddfSDavid du Colombier if (code < 0)
2917dd7cddfSDavid du Colombier goto fail;
2923ff48bf5SDavid du Colombier ops = gs_alloc_string(mem, size + 1, "gs_build_function_4(ops)");
2933ff48bf5SDavid du Colombier if (ops == 0) {
2947dd7cddfSDavid du Colombier code = gs_note_error(e_VMerror);
2957dd7cddfSDavid du Colombier goto fail;
2967dd7cddfSDavid du Colombier }
2973ff48bf5SDavid du Colombier size = 0;
2983ff48bf5SDavid du Colombier check_psc_function(i_ctx_p, proc, 0, ops, &size); /* can't fail */
2993ff48bf5SDavid du Colombier ops[size] = PtCr_return;
3003ff48bf5SDavid du Colombier params.ops.data = ops;
3013ff48bf5SDavid du Colombier params.ops.size = size + 1;
3023ff48bf5SDavid du Colombier code = gs_function_PtCr_init(ppfn, ¶ms, mem);
3037dd7cddfSDavid du Colombier if (code >= 0)
3047dd7cddfSDavid du Colombier return 0;
3053ff48bf5SDavid du Colombier /* free_params will free the ops string */
3067dd7cddfSDavid du Colombier fail:
3073ff48bf5SDavid du Colombier gs_function_PtCr_free_params(¶ms, mem);
3087dd7cddfSDavid du Colombier return (code < 0 ? code : gs_note_error(e_rangecheck));
3097dd7cddfSDavid du Colombier }
310