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 *)¶ms = *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, ¶ms, mem);
303 if (code >= 0)
304 return 0;
305 /* free_params will free the ops string */
306 fail:
307 gs_function_PtCr_free_params(¶ms, mem);
308 return (code < 0 ? code : gs_note_error(e_rangecheck));
309 }
310