xref: /plan9/sys/src/cmd/gs/src/zfunc4.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1999, 2000 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: zfunc4.c,v 1.12 2004/08/04 19:36:13 stefan Exp $ */
18 /* PostScript language support for FunctionType 4 (PS Calculator) Functions */
19 #include "memory_.h"
20 #include "ghost.h"
21 #include "oper.h"
22 #include "opextern.h"
23 #include "gsfunc.h"
24 #include "gsfunc4.h"
25 #include "gsutil.h"
26 #include "idict.h"
27 #include "ifunc.h"
28 #include "iname.h"
29 #include "dstack.h"
30 #include "ialloc.h"
31 /*
32  * FunctionType 4 functions are not defined in the PostScript language.  We
33  * provide support for them because they are needed for PDF 1.3.  In
34  * addition to the standard FunctionType, Domain, and Range keys, they have
35  * a Function key whose value is a procedure in a restricted subset of the
36  * PostScript language.  Specifically, the procedure must (recursively)
37  * contain only integer, real, Boolean, and procedure constants (only as
38  * literal operands of if and and ifelse), and operators chosen from the set
39  * given below.  Note that names other than true and false are not allowed:
40  * the procedure must be 'bound'.
41  *
42  * The following list is taken directly from the PDF 1.3 documentation.
43  */
44 #define XOP(zfn) int zfn(i_ctx_t *)
45 XOP(zabs); XOP(zand); XOP(zatan); XOP(zbitshift);
46 XOP(zceiling); XOP(zcos); XOP(zcvi); XOP(zcvr);
47 XOP(zdiv); XOP(zexp); XOP(zfloor); XOP(zidiv);
48 XOP(zln); XOP(zlog); XOP(zmod); XOP(zmul);
49 XOP(zneg); XOP(znot); XOP(zor); XOP(zround);
50 XOP(zsin); XOP(zsqrt); XOP(ztruncate); XOP(zxor);
51 XOP(zeq); XOP(zge); XOP(zgt); XOP(zle); XOP(zlt); XOP(zne);
52 XOP(z2copy);
53 #undef XOP
54 typedef struct calc_op_s {
55     op_proc_t proc;
56     gs_PtCr_opcode_t opcode;
57 } calc_op_t;
58 static const calc_op_t calc_ops[] = {
59 
60     /* Arithmetic operators */
61 
62     {zabs, PtCr_abs},
63     {zadd, PtCr_add},
64     {zand, PtCr_and},
65     {zatan, PtCr_atan},
66     {zbitshift, PtCr_bitshift},
67     {zceiling, PtCr_ceiling},
68     {zcos, PtCr_cos},
69     {zcvi, PtCr_cvi},
70     {zcvr, PtCr_cvr},
71     {zdiv, PtCr_div},
72     {zexp, PtCr_exp},
73     {zfloor, PtCr_floor},
74     {zidiv, PtCr_idiv},
75     {zln, PtCr_ln},
76     {zlog, PtCr_log},
77     {zmod, PtCr_mod},
78     {zmul, PtCr_mul},
79     {zneg, PtCr_neg},
80     {znot, PtCr_not},
81     {zor, PtCr_or},
82     {zround, PtCr_round},
83     {zsin, PtCr_sin},
84     {zsqrt, PtCr_sqrt},
85     {zsub, PtCr_sub},
86     {ztruncate, PtCr_truncate},
87     {zxor, PtCr_xor},
88 
89     /* Comparison operators */
90 
91     {zeq, PtCr_eq},
92     {zge, PtCr_ge},
93     {zgt, PtCr_gt},
94     {zle, PtCr_le},
95     {zlt, PtCr_lt},
96     {zne, PtCr_ne},
97 
98     /* Stack operators */
99 
100     {zcopy, PtCr_copy},
101     {z2copy, PtCr_copy},
102     {zdup, PtCr_dup},
103     {zexch, PtCr_exch},
104     {zindex, PtCr_index},
105     {zpop, PtCr_pop},
106     {zroll, PtCr_roll}
107 
108     /* Special operators */
109 
110     /*{zif, PtCr_if},*/
111     /*{zifelse, PtCr_ifelse},*/
112     /*{ztrue, PtCr_true},*/
113     /*{zfalse, PtCr_false}*/
114 };
115 
116 /* Fix up an if or ifelse forward reference. */
117 private void
psc_fixup(byte * p,byte * to)118 psc_fixup(byte *p, byte *to)
119 {
120     int skip = to - (p + 3);
121 
122     p[1] = (byte)(skip >> 8);
123     p[2] = (byte)skip;
124 }
125 
126 /*
127  * Check a calculator function for validity, optionally storing its encoded
128  * representation and add the size of the encoded representation to *psize.
129  * Note that we arbitrarily limit the depth of procedure nesting.  pref is
130  * known to be a procedure.
131  */
132 #define MAX_PSC_FUNCTION_NESTING 10
133 private int
check_psc_function(i_ctx_t * i_ctx_p,const ref * pref,int depth,byte * ops,int * psize)134 check_psc_function(i_ctx_t *i_ctx_p, const ref *pref, int depth, byte *ops, int *psize)
135 {
136     long i;
137     uint size = r_size(pref);
138 
139     for (i = 0; i < size; ++i) {
140 	byte no_ops[1 + max(sizeof(int), sizeof(float))];
141 	byte *p = (ops ? ops + *psize : no_ops);
142 	ref elt, elt2, elt3;
143 	ref * delp;
144 	int code;
145 
146 	array_get(imemory, pref, i, &elt);
147 	switch (r_btype(&elt)) {
148 	case t_integer: {
149 	    int i = elt.value.intval;
150 
151 #if ARCH_SIZEOF_INT < ARCH_SIZEOF_LONG
152 	    if (i != elt.value.intval) /* check for truncation */
153 		return_error(e_rangecheck);
154 #endif
155 	    if (i == (byte)i) {
156 		*p = PtCr_byte;
157 		p[1] = (byte)i;
158 		*psize += 2;
159 	    } else {
160 		*p = PtCr_int;
161 		memcpy(p + 1, &i, sizeof(i));
162 		*psize += 1 + sizeof(int);
163 	    }
164 	    break;
165 	}
166 	case t_real: {
167 	    float f = elt.value.realval;
168 
169 	    *p = PtCr_float;
170 	    memcpy(p + 1, &f, sizeof(f));
171 	    *psize += 1 + sizeof(float);
172 	    break;
173 	}
174 	case t_boolean:
175 	    *p = (elt.value.boolval ? PtCr_true : PtCr_false);
176 	    ++*psize;
177 	    break;
178 	case t_name:
179 	    if (!r_has_attr(&elt, a_executable))
180 		return_error(e_rangecheck);
181 	    name_string_ref(imemory, &elt, &elt);
182 	    if (!bytes_compare(elt.value.bytes, r_size(&elt),
183 			       (const byte *)"true", 4)) {
184 		*p = PtCr_true;
185 	        ++*psize;
186 	        break;
187 	    }
188 	    if (!bytes_compare(elt.value.bytes, r_size(&elt),
189 				      (const byte *)"false", 5)) {
190 		*p = PtCr_false;
191 	        ++*psize;
192 	        break;
193 	    }
194 	    /* Check if the name is a valid operator in systemdict */
195 	    if (dict_find(systemdict, &elt, &delp) <= 0)
196 		return_error(e_undefined);
197 	    if (r_btype(delp) != t_operator)
198 		return_error(e_typecheck);
199 	    if (!r_has_attr(delp, a_executable))
200 		return_error(e_rangecheck);
201 	    elt = *delp;
202 	    /* Fall into the operator case */
203 	case t_operator: {
204 	    int j;
205 
206 	    for (j = 0; j < countof(calc_ops); ++j)
207 		if (elt.value.opproc == calc_ops[j].proc) {
208 		    *p = calc_ops[j].opcode;
209 		    ++*psize;
210 		    goto next;
211 		}
212 	    return_error(e_rangecheck);
213 	}
214 	default: {
215 	    if (!r_is_proc(&elt))
216 		return_error(e_typecheck);
217 	    if (depth == MAX_PSC_FUNCTION_NESTING)
218 		return_error(e_limitcheck);
219 	    if ((code = array_get(imemory, pref, ++i, &elt2)) < 0)
220 		return code;
221 	    *psize += 3;
222 	    code = check_psc_function(i_ctx_p, &elt, depth + 1, ops, psize);
223 	    if (code < 0)
224 		return code;
225 	    /* Check for {proc} if | {proc1} {proc2} ifelse */
226 #define R_IS_OPER(pref, proc)\
227   (r_btype(pref) == t_operator && r_has_attr(pref, a_executable) &&\
228    (pref)->value.opproc == proc)
229 	    if (R_IS_OPER(&elt2, zif)) {
230 		if (ops) {
231 		    *p = PtCr_if;
232 		    psc_fixup(p, ops + *psize);
233 		}
234 	    } else if (!r_is_proc(&elt2))
235 		return_error(e_rangecheck);
236 	    else if ((code == array_get(imemory, pref, ++i, &elt3)) < 0)
237 		return code;
238 	    else if (R_IS_OPER(&elt3, zifelse)) {
239 		if (ops) {
240 		    *p = PtCr_if;
241 		    psc_fixup(p, ops + *psize + 3);
242 		    p = ops + *psize;
243 		    *p = PtCr_else;
244 		}
245 		*psize += 3;
246 		code = check_psc_function(i_ctx_p, &elt2, depth + 1, ops, psize);
247 		if (code < 0)
248 		    return code;
249 		if (ops)
250 		    psc_fixup(p, ops + *psize);
251 	    } else
252 		return_error(e_rangecheck);
253 #undef R_IS_OPER
254 	}
255 	}
256     next:
257 	DO_NOTHING;
258     }
259     return 0;
260 }
261 #undef MAX_PSC_FUNCTION_NESTING
262 
263 /* Check prototype */
264 build_function_proc(gs_build_function_4);
265 
266 /* Finish building a FunctionType 4 (PostScript Calculator) function. */
267 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)268 gs_build_function_4(i_ctx_t *i_ctx_p, const ref *op, const gs_function_params_t * mnDR,
269 		    int depth, gs_function_t ** ppfn, gs_memory_t *mem)
270 {
271     gs_function_PtCr_params_t params;
272     ref *proc;
273     int code;
274     byte *ops;
275     int size;
276 
277     *(gs_function_params_t *)&params = *mnDR;
278     params.ops.data = 0;	/* in case of failure */
279     params.ops.size = 0;	/* ditto */
280     if (dict_find_string(op, "Function", &proc) <= 0) {
281 	code = gs_note_error(e_rangecheck);
282 	goto fail;
283     }
284     if (!r_is_proc(proc)) {
285 	code = gs_note_error(e_typecheck);
286 	goto fail;
287     }
288     size = 0;
289     code = check_psc_function(i_ctx_p, proc, 0, NULL, &size);
290     if (code < 0)
291 	goto fail;
292     ops = gs_alloc_string(mem, size + 1, "gs_build_function_4(ops)");
293     if (ops == 0) {
294 	code = gs_note_error(e_VMerror);
295 	goto fail;
296     }
297     size = 0;
298     check_psc_function(i_ctx_p, proc, 0, ops, &size); /* can't fail */
299     ops[size] = PtCr_return;
300     params.ops.data = ops;
301     params.ops.size = size + 1;
302     code = gs_function_PtCr_init(ppfn, &params, mem);
303     if (code >= 0)
304 	return 0;
305     /* free_params will free the ops string */
306 fail:
307     gs_function_PtCr_free_params(&params, mem);
308     return (code < 0 ? code : gs_note_error(e_rangecheck));
309 }
310