1 /* Copyright (C) 2001-2006 Artifex Software, Inc.
2 All Rights Reserved.
3
4 This software is provided AS-IS with no warranty, either express or
5 implied.
6
7 This software is distributed under license and may not be copied, modified
8 or distributed except as expressly authorized under the terms of that
9 license. Refer to licensing information at http://www.artifex.com/
10 or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11 San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
12 */
13
14 /* $Id: zfunc4.c 9778 2009-06-05 05:55:54Z alexcher $ */
15 /* PostScript language support for FunctionType 4 (PS Calculator) Functions */
16 #include "memory_.h"
17 #include "ghost.h"
18 #include "oper.h"
19 #include "opextern.h"
20 #include "gsfunc.h"
21 #include "gsfunc4.h"
22 #include "gsutil.h"
23 #include "idict.h"
24 #include "ifunc.h"
25 #include "iname.h"
26 #include "dstack.h"
27 #include "ialloc.h"
28 #include "gzstate.h" /* these are needed to check if device is pdfwrite */
29 #include "gxdevcli.h" /* these are needed to check if device is pdfwrite */
30 #include "string_.h" /* these are needed to check if device is pdfwrite */
31 #include "zfunc.h"
32 #include "zcolor.h"
33
34 /*
35 * FunctionType 4 functions are not defined in the PostScript language. We
36 * provide support for them because they are needed for PDF 1.3. In
37 * addition to the standard FunctionType, Domain, and Range keys, they have
38 * a Function key whose value is a procedure in a restricted subset of the
39 * PostScript language. Specifically, the procedure must (recursively)
40 * contain only integer, real, Boolean, and procedure constants (only as
41 * literal operands of if and and ifelse), and operators chosen from the set
42 * given below. Note that names other than true and false are not allowed:
43 * the procedure must be 'bound'.
44 *
45 * The following list is taken directly from the PDF 1.3 documentation.
46 */
47 #define XOP(zfn) int zfn(i_ctx_t *)
48 XOP(zabs); XOP(zand); XOP(zatan); XOP(zbitshift);
49 XOP(zceiling); XOP(zcos); XOP(zcvi); XOP(zcvr);
50 XOP(zdiv); XOP(zexp); XOP(zfloor); XOP(zidiv);
51 XOP(zln); XOP(zlog); XOP(zmod); XOP(zmul);
52 XOP(zneg); XOP(znot); XOP(zor); XOP(zround);
53 XOP(zsin); XOP(zsqrt); XOP(ztruncate); XOP(zxor);
54 XOP(zeq); XOP(zge); XOP(zgt); XOP(zle); XOP(zlt); XOP(zne);
55 XOP(z2copy);
56 #undef XOP
57 typedef struct calc_op_s {
58 op_proc_t proc;
59 gs_PtCr_opcode_t opcode;
60 } calc_op_t;
61 static const calc_op_t calc_ops[] = {
62
63 /* Arithmetic operators */
64
65 {zabs, PtCr_abs},
66 {zadd, PtCr_add},
67 {zand, PtCr_and},
68 {zatan, PtCr_atan},
69 {zbitshift, PtCr_bitshift},
70 {zceiling, PtCr_ceiling},
71 {zcos, PtCr_cos},
72 {zcvi, PtCr_cvi},
73 {zcvr, PtCr_cvr},
74 {zdiv, PtCr_div},
75 {zexp, PtCr_exp},
76 {zfloor, PtCr_floor},
77 {zidiv, PtCr_idiv},
78 {zln, PtCr_ln},
79 {zlog, PtCr_log},
80 {zmod, PtCr_mod},
81 {zmul, PtCr_mul},
82 {zneg, PtCr_neg},
83 {znot, PtCr_not},
84 {zor, PtCr_or},
85 {zround, PtCr_round},
86 {zsin, PtCr_sin},
87 {zsqrt, PtCr_sqrt},
88 {zsub, PtCr_sub},
89 {ztruncate, PtCr_truncate},
90 {zxor, PtCr_xor},
91
92 /* Comparison operators */
93
94 {zeq, PtCr_eq},
95 {zge, PtCr_ge},
96 {zgt, PtCr_gt},
97 {zle, PtCr_le},
98 {zlt, PtCr_lt},
99 {zne, PtCr_ne},
100
101 /* Stack operators */
102
103 {zcopy, PtCr_copy},
104 {z2copy, PtCr_copy},
105 {zdup, PtCr_dup},
106 {zexch, PtCr_exch},
107 {zindex, PtCr_index},
108 {zpop, PtCr_pop},
109 {zroll, PtCr_roll}
110
111 /* Special operators */
112
113 /*{zif, PtCr_if},*/
114 /*{zifelse, PtCr_ifelse},*/
115 /*{ztrue, PtCr_true},*/
116 /*{zfalse, PtCr_false}*/
117 };
118
119 /* Fix up an if or ifelse forward reference. */
120 static void
psc_fixup(byte * p,byte * to)121 psc_fixup(byte *p, byte *to)
122 {
123 int skip = to - (p + 3);
124
125 p[1] = (byte)(skip >> 8);
126 p[2] = (byte)skip;
127 }
128
129 /* Check whether the ref is a given operator or resolves to it */
130 static bool
resolves_to_oper(i_ctx_t * i_ctx_p,const ref * pref,const op_proc_t proc)131 resolves_to_oper(i_ctx_t *i_ctx_p, const ref *pref, const op_proc_t proc)
132 {
133 if (!r_has_attr(pref, a_executable))
134 return false;
135 if (r_btype(pref) == t_operator) {
136 return pref->value.opproc == proc;
137 } else if (r_btype(pref) == t_name) {
138 ref * val;
139 if (dict_find(systemdict, pref, &val) <= 0)
140 return false;
141 if (r_btype(val) != t_operator)
142 return false;
143 if (!r_has_attr(val, a_executable))
144 return false;
145 return val->value.opproc == proc;
146 }
147 else
148 return false;
149 }
150
151 /*
152 * Check a calculator function for validity, optionally storing its encoded
153 * representation and add the size of the encoded representation to *psize.
154 * Note that we arbitrarily limit the depth of procedure nesting. pref is
155 * known to be a procedure.
156 */
157 static int
check_psc_function(i_ctx_t * i_ctx_p,const ref * pref,int depth,byte * ops,int * psize)158 check_psc_function(i_ctx_t *i_ctx_p, const ref *pref, int depth, byte *ops, int *psize)
159 {
160 uint i;
161 uint size = r_size(pref);
162
163 for (i = 0; i < size; ++i) {
164 byte no_ops[1 + max(sizeof(int), sizeof(float))];
165 byte *p = (ops ? ops + *psize : no_ops);
166 ref elt, elt2, elt3;
167 ref * delp;
168 int code;
169
170 array_get(imemory, pref, i, &elt);
171 switch (r_btype(&elt)) {
172 case t_integer: {
173 int i = elt.value.intval;
174
175 if (i == (byte)i) {
176 *p = PtCr_byte;
177 p[1] = (byte)i;
178 *psize += 2;
179 } else {
180 *p = PtCr_int;
181 memcpy(p + 1, &i, sizeof(i));
182 *psize += 1 + sizeof(int);
183 }
184 break;
185 }
186 case t_real: {
187 float f = elt.value.realval;
188
189 *p = PtCr_float;
190 memcpy(p + 1, &f, sizeof(f));
191 *psize += 1 + sizeof(float);
192 break;
193 }
194 case t_boolean:
195 *p = (elt.value.boolval ? PtCr_true : PtCr_false);
196 ++*psize;
197 break;
198 case t_name:
199 if (!r_has_attr(&elt, a_executable))
200 return_error(e_rangecheck);
201 name_string_ref(imemory, &elt, &elt);
202 if (!bytes_compare(elt.value.bytes, r_size(&elt),
203 (const byte *)"true", 4)) {
204 *p = PtCr_true;
205 ++*psize;
206 break;
207 }
208 if (!bytes_compare(elt.value.bytes, r_size(&elt),
209 (const byte *)"false", 5)) {
210 *p = PtCr_false;
211 ++*psize;
212 break;
213 }
214 /* Check if the name is a valid operator in systemdict */
215 if (dict_find(systemdict, &elt, &delp) <= 0)
216 return_error(e_undefined);
217 if (r_btype(delp) != t_operator)
218 return_error(e_typecheck);
219 if (!r_has_attr(delp, a_executable))
220 return_error(e_rangecheck);
221 elt = *delp;
222 /* Fall into the operator case */
223 case t_operator: {
224 int j;
225
226 for (j = 0; j < countof(calc_ops); ++j)
227 if (elt.value.opproc == calc_ops[j].proc) {
228 *p = calc_ops[j].opcode;
229 ++*psize;
230 goto next;
231 }
232 return_error(e_rangecheck);
233 }
234 default: {
235 if (!r_is_proc(&elt))
236 return_error(e_typecheck);
237 if (depth == MAX_PSC_FUNCTION_NESTING)
238 return_error(e_limitcheck);
239 if ((code = array_get(imemory, pref, ++i, &elt2)) < 0)
240 return code;
241 *psize += 3;
242 code = check_psc_function(i_ctx_p, &elt, depth + 1, ops, psize);
243 if (code < 0)
244 return code;
245 /* Check for { proc } repeat | {proc} if | {proc1} {proc2} ifelse */
246 if (resolves_to_oper(i_ctx_p, &elt2, zrepeat)) {
247 /* We can't handle 'repeat' with pdfwrite since it emits FunctionType 4 */
248 if (strcmp(i_ctx_p->pgs->device->dname, "pdfwrite") == 0)
249 return_error(e_rangecheck);
250 if (ops) {
251 *p = PtCr_repeat;
252 psc_fixup(p, ops + *psize);
253 p = ops + *psize;
254 *p++ = PtCr_repeat_end;
255 }
256 *psize += 1; /* extra room for repeat_end */
257 } else if (resolves_to_oper(i_ctx_p, &elt2, zif)) {
258 if (ops) {
259 *p = PtCr_if;
260 psc_fixup(p, ops + *psize);
261 }
262 } else if (!r_is_proc(&elt2))
263 return_error(e_rangecheck);
264 else if ((code = array_get(imemory, pref, ++i, &elt3)) < 0)
265 return code;
266 else if (resolves_to_oper(i_ctx_p, &elt3, zifelse)) {
267 if (ops) {
268 *p = PtCr_if;
269 psc_fixup(p, ops + *psize + 3);
270 p = ops + *psize;
271 *p = PtCr_else;
272 }
273 *psize += 3;
274 code = check_psc_function(i_ctx_p, &elt2, depth + 1, ops, psize);
275 if (code < 0)
276 return code;
277 if (ops)
278 psc_fixup(p, ops + *psize);
279 } else
280 return_error(e_rangecheck);
281 } /* end 'default' */
282 }
283 next:
284 DO_NOTHING;
285 }
286 return 0;
287 }
288 #undef MAX_PSC_FUNCTION_NESTING
289
290 /* Check prototype */
291 build_function_proc(gs_build_function_4);
292
293 /* Finish building a FunctionType 4 (PostScript Calculator) function. */
294 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)295 gs_build_function_4(i_ctx_t *i_ctx_p, const ref *op, const gs_function_params_t * mnDR,
296 int depth, gs_function_t ** ppfn, gs_memory_t *mem)
297 {
298 gs_function_PtCr_params_t params;
299 ref *proc;
300 int code;
301 byte *ops;
302 int size;
303
304 *(gs_function_params_t *)¶ms = *mnDR;
305 params.ops.data = 0; /* in case of failure */
306 params.ops.size = 0; /* ditto */
307 if (dict_find_string(op, "Function", &proc) <= 0) {
308 code = gs_note_error(e_rangecheck);
309 goto fail;
310 }
311 if (!r_is_proc(proc)) {
312 code = gs_note_error(e_typecheck);
313 goto fail;
314 }
315 size = 0;
316 code = check_psc_function(i_ctx_p, proc, 0, NULL, &size);
317 if (code < 0)
318 goto fail;
319 ops = gs_alloc_string(mem, size + 1, "gs_build_function_4(ops)");
320 if (ops == 0) {
321 code = gs_note_error(e_VMerror);
322 goto fail;
323 }
324 size = 0;
325 check_psc_function(i_ctx_p, proc, 0, ops, &size); /* can't fail */
326 ops[size] = PtCr_return;
327 params.ops.data = ops;
328 params.ops.size = size + 1;
329 code = gs_function_PtCr_init(ppfn, ¶ms, mem);
330 if (code >= 0)
331 return 0;
332 /* free_params will free the ops string */
333 fail:
334 gs_function_PtCr_free_params(¶ms, mem);
335 return (code < 0 ? code : gs_note_error(e_rangecheck));
336 }
337
make_type4_function(i_ctx_t * i_ctx_p,ref * arr,ref * pproc,gs_function_t ** func)338 int make_type4_function(i_ctx_t * i_ctx_p, ref *arr, ref *pproc, gs_function_t **func)
339 {
340 int code, size, num_components, CIESubst;
341 byte *ops;
342 gs_function_PtCr_params_t params;
343 float *ptr;
344 ref alternatespace, *palternatespace = &alternatespace;
345 PS_colour_space_t *space, *altspace;
346
347 code = get_space_object(i_ctx_p, arr, &space);
348 if (code < 0)
349 return code;
350 if (!space->alternateproc)
351 return e_typecheck;
352 code = space->alternateproc(i_ctx_p, arr, &palternatespace, &CIESubst);
353 if (code < 0)
354 return code;
355 code = get_space_object(i_ctx_p, palternatespace, &altspace);
356 if (code < 0)
357 return code;
358
359 code = space->numcomponents(i_ctx_p, arr, &num_components);
360 if (code < 0)
361 return code;
362 ptr = (float *)gs_alloc_byte_array(imemory, num_components * 2, sizeof(float), "make_type4_function(Domain)");
363 if (!ptr)
364 return e_VMerror;
365 code = space->domain(i_ctx_p, arr, ptr);
366 if (code < 0) {
367 gs_free_const_object(imemory, ptr, "make_type4_function(Domain)");
368 return code;
369 }
370 params.Domain = ptr;
371 params.m = num_components;
372
373 code = altspace->numcomponents(i_ctx_p, &alternatespace, &num_components);
374 if (code < 0) {
375 gs_free_const_object(imemory, params.Domain, "make_type4_function(Domain)");
376 return code;
377 }
378 ptr = (float *)gs_alloc_byte_array(imemory, num_components * 2, sizeof(float), "make_type4_function(Range)");
379 if (!ptr) {
380 gs_free_const_object(imemory, params.Domain, "make_type4_function(Domain)");
381 return e_VMerror;
382 }
383 code = altspace->range(i_ctx_p, &alternatespace, ptr);
384 if (code < 0) {
385 gs_free_const_object(imemory, ptr, "make_type4_function(Domain)");
386 gs_free_const_object(imemory, params.Domain, "make_type4_function(Range)");
387 return code;
388 }
389 params.Range = ptr;
390 params.n = num_components;
391
392 params.ops.data = 0; /* in case of failure, see gs_function_PtCr_free_params */
393 params.ops.size = 0; /* ditto */
394 size = 0;
395 code = check_psc_function(i_ctx_p, (const ref *)pproc, 0, NULL, &size);
396 if (code < 0) {
397 gs_function_PtCr_free_params(¶ms, imemory);
398 return code;
399 }
400 ops = gs_alloc_string(imemory, size + 1, "make_type4_function(ops)");
401 size = 0;
402 check_psc_function(i_ctx_p, (const ref *)pproc, 0, ops, &size); /* can't fail */
403 ops[size] = PtCr_return;
404 params.ops.data = ops;
405 params.ops.size = size + 1;
406 code = gs_function_PtCr_init(func, ¶ms, imemory);
407 if (code < 0)
408 gs_function_PtCr_free_params(¶ms, imemory);
409
410 return code;
411 }
412