1 /* Copyright (C) 2001-2012 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,
8 modified or distributed except as expressly authorized under the terms
9 of the license contained in the file LICENSE in this distribution.
10
11 Refer to licensing information at http://www.artifex.com or contact
12 Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
13 CA 94903, U.S.A., +1(415)492-9861, for further information.
14 */
15
16
17 /* PostScript language support for FunctionType 4 (PS Calculator) Functions */
18 #include "memory_.h"
19 #include "ghost.h"
20 #include "oper.h"
21 #include "opextern.h"
22 #include "gsfunc.h"
23 #include "gsfunc4.h"
24 #include "gsutil.h"
25 #include "idict.h"
26 #include "ifunc.h"
27 #include "iname.h"
28 #include "dstack.h"
29 #include "ialloc.h"
30 #include "gzstate.h" /* these are needed to check device parameters */
31 #include "gsparam.h" /* these are needed to check device parameters */
32 #include "zfunc.h"
33 #include "zcolor.h"
34
35 /*
36 * FunctionType 4 functions are not defined in the PostScript language. We
37 * provide support for them because they are needed for PDF 1.3. In
38 * addition to the standard FunctionType, Domain, and Range keys, they have
39 * a Function key whose value is a procedure in a restricted subset of the
40 * PostScript language. Specifically, the procedure must (recursively)
41 * contain only integer, real, Boolean, and procedure constants (only as
42 * literal operands of if and and ifelse), and operators chosen from the set
43 * given below. Note that names other than true and false are not allowed:
44 * the procedure must be 'bound'.
45 *
46 * The following list is taken directly from the PDF 1.3 documentation.
47 */
48 #define XOP(zfn) int zfn(i_ctx_t *)
49 XOP(zabs); XOP(zand); XOP(zatan); XOP(zbitshift);
50 XOP(zceiling); XOP(zcos); XOP(zcvi); XOP(zcvr);
51 XOP(zdiv); XOP(zexp); XOP(zfloor); XOP(zidiv);
52 XOP(zln); XOP(zlog); XOP(zmod); XOP(zmul);
53 XOP(zneg); XOP(znot); XOP(zor); XOP(zround);
54 XOP(zsin); XOP(zsqrt); XOP(ztruncate); XOP(zxor);
55 XOP(zeq); XOP(zge); XOP(zgt); XOP(zle); XOP(zlt); XOP(zne);
56 XOP(z2copy);
57 #undef XOP
58 typedef struct calc_op_s {
59 op_proc_t proc;
60 gs_PtCr_opcode_t opcode;
61 } calc_op_t;
62 static const calc_op_t calc_ops[] = {
63
64 /* Arithmetic operators */
65
66 {zabs, PtCr_abs},
67 {zadd, PtCr_add},
68 {zand, PtCr_and},
69 {zatan, PtCr_atan},
70 {zbitshift, PtCr_bitshift},
71 {zceiling, PtCr_ceiling},
72 {zcos, PtCr_cos},
73 {zcvi, PtCr_cvi},
74 {zcvr, PtCr_cvr},
75 {zdiv, PtCr_div},
76 {zexp, PtCr_exp},
77 {zfloor, PtCr_floor},
78 {zidiv, PtCr_idiv},
79 {zln, PtCr_ln},
80 {zlog, PtCr_log},
81 {zmod, PtCr_mod},
82 {zmul, PtCr_mul},
83 {zneg, PtCr_neg},
84 {znot, PtCr_not},
85 {zor, PtCr_or},
86 {zround, PtCr_round},
87 {zsin, PtCr_sin},
88 {zsqrt, PtCr_sqrt},
89 {zsub, PtCr_sub},
90 {ztruncate, PtCr_truncate},
91 {zxor, PtCr_xor},
92
93 /* Comparison operators */
94
95 {zeq, PtCr_eq},
96 {zge, PtCr_ge},
97 {zgt, PtCr_gt},
98 {zle, PtCr_le},
99 {zlt, PtCr_lt},
100 {zne, PtCr_ne},
101
102 /* Stack operators */
103
104 {zcopy, PtCr_copy},
105 {z2copy, PtCr_copy},
106 {zdup, PtCr_dup},
107 {zexch, PtCr_exch},
108 {zindex, PtCr_index},
109 {zpop, PtCr_pop},
110 {zroll, PtCr_roll}
111
112 /* Special operators */
113
114 /*{zif, PtCr_if},*/
115 /*{zifelse, PtCr_ifelse},*/
116 /*{ztrue, PtCr_true},*/
117 /*{zfalse, PtCr_false}*/
118 };
119
120 /* Fix up an if or ifelse forward reference. */
121 static void
psc_fixup(byte * p,byte * to)122 psc_fixup(byte *p, byte *to)
123 {
124 int skip = to - (p + 3);
125
126 p[1] = (byte)(skip >> 8);
127 p[2] = (byte)skip;
128 }
129
130 /* Check whether the ref is a given operator or resolves to it */
131 static bool
resolves_to_oper(i_ctx_t * i_ctx_p,const ref * pref,const op_proc_t proc)132 resolves_to_oper(i_ctx_t *i_ctx_p, const ref *pref, const op_proc_t proc)
133 {
134 if (!r_has_attr(pref, a_executable))
135 return false;
136 if (r_btype(pref) == t_operator) {
137 return pref->value.opproc == proc;
138 } else if (r_btype(pref) == t_name) {
139 ref * val;
140 if (dict_find(systemdict, pref, &val) <= 0)
141 return false;
142 if (r_btype(val) != t_operator)
143 return false;
144 if (!r_has_attr(val, a_executable))
145 return false;
146 return val->value.opproc == proc;
147 }
148 else
149 return false;
150 }
151
152 /* Store an int in the buffer */
153 static int
put_int(byte ** p,int n)154 put_int(byte **p, int n) {
155 if (n == (byte)n) {
156 if (*p) {
157 (*p)[0] = PtCr_byte;
158 (*p)[1] = (byte)n;
159 *p += 2;
160 }
161 return 2;
162 } else {
163 if (*p) {
164 **p = PtCr_int;
165 memcpy(*p + 1, &n, sizeof(int));
166 *p += sizeof(int) + 1;
167 }
168 return (sizeof(int) + 1);
169 }
170 }
171
172 /* Store a float in the buffer */
173 static int
put_float(byte ** p,float n)174 put_float(byte **p, float n) {
175 if (*p) {
176 **p = PtCr_float;
177 memcpy(*p + 1, &n, sizeof(float));
178 *p += sizeof(float) + 1;
179 }
180 return (sizeof(float) + 1);
181 }
182
183 /* Store an op code in the buffer */
184 static int
put_op(byte ** p,byte op)185 put_op(byte **p, byte op) {
186 if (*p)
187 *(*p)++ = op;
188 return 1;
189 }
190
191 /*
192 * Check a calculator function for validity, optionally storing its encoded
193 * representation and add the size of the encoded representation to *psize.
194 * Note that we arbitrarily limit the depth of procedure nesting. pref is
195 * known to be a procedure.
196 */
197 static int
check_psc_function(i_ctx_t * i_ctx_p,const ref * pref,int depth,byte * ops,int * psize)198 check_psc_function(i_ctx_t *i_ctx_p, const ref *pref, int depth, byte *ops, int *psize)
199 {
200 int code;
201 uint i, j;
202 uint size = r_size(pref);
203 byte *p;
204
205 if (size == 2 && depth == 0) {
206 /* Bug 690986. Recognize and replace Corel tint transform function.
207 { tint_params CorelTintTransformFunction }
208
209 Where tint_params resolves to an arrey like:
210 [ 1.0 0.0 0.0 0.0
211 0.0 1.0 0.0 0.0
212 0.0 0.0 1.0 0.0
213 0.0 0.0 0.0 1.0
214 0.2 0.81 0.76 0.61
215 ]
216 And CorelTintTransformFunction is:
217 { /colorantSpecArray exch def
218 /nColorants colorantSpecArray length 4 idiv def
219 /inColor nColorants 1 add 1 roll nColorants array astore def
220 /outColor 4 array def
221 0 1 3 {
222 /nOutInk exch def
223 1
224 0 1 nColorants 1 sub {
225 dup inColor exch get
226 exch 4 mul nOutInk add colorantSpecArray exch get mul
227 1 exch sub mul
228 } for
229 1 exch sub
230 outColor nOutInk 3 -1 roll put
231 } for
232 outColor aload pop
233 }
234 */
235 ref r_tp, r_cttf; /* original references */
236 ref n_tp, n_cttf; /* names */
237 ref *v_tp, *v_cttf; /* values */
238 int sz;
239
240 p = ops;
241 sz = *psize;
242 if(array_get(imemory, pref, 0, &r_tp) < 0)
243 goto idiom_failed;
244 if (array_get(imemory, pref, 1, &r_cttf) < 0)
245 goto idiom_failed;
246 if (r_has_type(&r_tp, t_name) && r_has_type(&r_cttf, t_name)) {
247 if ((code = name_enter_string(imemory, "tint_params", &n_tp)) < 0)
248 return code;
249 if (r_tp.value.pname == n_tp.value.pname) {
250 if ((code = name_enter_string(imemory, "CorelTintTransformFunction", &n_cttf)) < 0)
251 return code;
252 if (r_cttf.value.pname == n_cttf.value.pname) {
253 v_tp = dict_find_name(&n_tp);
254 v_cttf = dict_find_name(&n_cttf);
255 if (v_tp && v_cttf && r_is_array(v_tp) && r_is_array(v_cttf)) {
256 uint n_elem = r_size(v_tp);
257
258 if ((n_elem & 3) == 0 && r_size(v_cttf) == 31) {
259 /* Enough testing, idiom recognition tests less. */
260 uint n_col = n_elem/4;
261
262 for (i = 0; i < 4; i ++) {
263 ref v;
264 float fv;
265 bool first = true;
266
267 for (j = 0; j < n_col; j++) {
268 if (array_get(imemory, v_tp, j*4 + i, &v) < 0)
269 goto idiom_failed;
270 if (r_type(&v) == t_integer)
271 fv = (float)v.value.intval;
272 else if (r_type(&v) == t_real)
273 fv = v.value.realval;
274 else
275 goto idiom_failed;
276
277 if (fv != 0.) {
278 if (first)
279 sz += put_int(&p, 1);
280 sz += put_int(&p, 1);
281 sz += put_int(&p, n_col + 1 - j + i + !first);
282 sz += put_op(&p, PtCr_index);
283 if (fv != 1.) {
284 sz += put_float(&p, fv);
285 sz += put_op(&p, PtCr_mul);
286 }
287 sz += put_op(&p, PtCr_sub);
288 if (first)
289 first = false;
290 else
291 sz += put_op(&p, PtCr_mul);
292 }
293 }
294 if (first)
295 sz += put_int(&p, 0);
296 else
297 sz += put_op(&p, PtCr_sub);
298 }
299 /* n_col+4 4 roll pop ... pop */
300 sz += put_int(&p, n_col + 4);
301 sz += put_int(&p, 4);
302 sz += put_op(&p, PtCr_roll);
303 for (j = 0; j < n_col; j++)
304 sz += put_op(&p, PtCr_pop);
305 *psize = sz;
306 return 0;
307 }
308 }
309 }
310 }
311 }
312 }
313 idiom_failed:;
314 for (i = 0; i < size; ++i) {
315 byte no_ops[1 + max(sizeof(int), sizeof(float))];
316 ref elt, elt2, elt3;
317 ref * delp;
318
319 p = (ops ? ops + *psize : no_ops);
320 array_get(imemory, pref, i, &elt);
321 switch (r_btype(&elt)) {
322 case t_integer:
323 *psize += put_int(&p, elt.value.intval);
324 break;
325 case t_real:
326 *psize += put_float(&p, elt.value.realval);
327 break;
328 case t_boolean:
329 *p = (elt.value.boolval ? PtCr_true : PtCr_false);
330 ++*psize;
331 break;
332 case t_name:
333 if (!r_has_attr(&elt, a_executable))
334 return_error(e_rangecheck);
335 name_string_ref(imemory, &elt, &elt);
336 if (!bytes_compare(elt.value.bytes, r_size(&elt),
337 (const byte *)"true", 4)) {
338 *p = PtCr_true;
339 ++*psize;
340 break;
341 }
342 if (!bytes_compare(elt.value.bytes, r_size(&elt),
343 (const byte *)"false", 5)) {
344 *p = PtCr_false;
345 ++*psize;
346 break;
347 }
348 /* Check if the name is a valid operator in systemdict */
349 if (dict_find(systemdict, &elt, &delp) <= 0)
350 return_error(e_undefined);
351 if (r_btype(delp) != t_operator)
352 return_error(e_typecheck);
353 if (!r_has_attr(delp, a_executable))
354 return_error(e_rangecheck);
355 elt = *delp;
356 /* Fall into the operator case */
357 case t_operator: {
358 int j;
359
360 for (j = 0; j < countof(calc_ops); ++j)
361 if (elt.value.opproc == calc_ops[j].proc) {
362 *p = calc_ops[j].opcode;
363 ++*psize;
364 goto next;
365 }
366 return_error(e_rangecheck);
367 }
368 default: {
369 if (!r_is_proc(&elt))
370 return_error(e_typecheck);
371 if (depth == MAX_PSC_FUNCTION_NESTING)
372 return_error(e_limitcheck);
373 if ((code = array_get(imemory, pref, ++i, &elt2)) < 0)
374 return code;
375 *psize += 3;
376 code = check_psc_function(i_ctx_p, &elt, depth + 1, ops, psize);
377 if (code < 0)
378 return code;
379 /* Check for { proc } repeat | {proc} if | {proc1} {proc2} ifelse */
380 if (resolves_to_oper(i_ctx_p, &elt2, zrepeat)) {
381 gs_c_param_list list;
382 int AllowRepeat = 1;
383
384 /* Check if the device allows the use of repeat in functions */
385 /* We can't handle 'repeat' with pdfwrite since it emits FunctionType 4 */
386 gs_c_param_list_write(&list, i_ctx_p->pgs->device->memory);
387 code = gs_getdeviceparams(i_ctx_p->pgs->device, (gs_param_list *)&list);
388 if (code < 0)
389 return code;
390 gs_c_param_list_read(&list);
391 code = param_read_bool((gs_param_list *)&list,
392 "AllowPSRepeatFunctions",
393 &AllowRepeat);
394 if (code < 0)
395 return code;
396 gs_c_param_list_release(&list);
397
398 if (!AllowRepeat)
399 return_error(e_rangecheck);
400 if (ops) {
401 *p = PtCr_repeat;
402 psc_fixup(p, ops + *psize);
403 p = ops + *psize;
404 *p++ = PtCr_repeat_end;
405 }
406 *psize += 1; /* extra room for repeat_end */
407 } else if (resolves_to_oper(i_ctx_p, &elt2, zif)) {
408 if (ops) {
409 *p = PtCr_if;
410 psc_fixup(p, ops + *psize);
411 }
412 } else if (!r_is_proc(&elt2))
413 return_error(e_rangecheck);
414 else if ((code = array_get(imemory, pref, ++i, &elt3)) < 0)
415 return code;
416 else if (resolves_to_oper(i_ctx_p, &elt3, zifelse)) {
417 if (ops) {
418 *p = PtCr_if;
419 psc_fixup(p, ops + *psize + 3);
420 p = ops + *psize;
421 *p = PtCr_else;
422 }
423 *psize += 3;
424 code = check_psc_function(i_ctx_p, &elt2, depth + 1, ops, psize);
425 if (code < 0)
426 return code;
427 if (ops)
428 psc_fixup(p, ops + *psize);
429 } else
430 return_error(e_rangecheck);
431 } /* end 'default' */
432 }
433 next:
434 DO_NOTHING;
435 }
436 return 0;
437 }
438 #undef MAX_PSC_FUNCTION_NESTING
439
440 /* Check prototype */
441 build_function_proc(gs_build_function_4);
442
443 /* Finish building a FunctionType 4 (PostScript Calculator) function. */
444 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)445 gs_build_function_4(i_ctx_t *i_ctx_p, const ref *op, const gs_function_params_t * mnDR,
446 int depth, gs_function_t ** ppfn, gs_memory_t *mem)
447 {
448 gs_function_PtCr_params_t params;
449 ref *proc;
450 int code;
451 byte *ops;
452 int size;
453
454 *(gs_function_params_t *)¶ms = *mnDR;
455 params.ops.data = 0; /* in case of failure */
456 params.ops.size = 0; /* ditto */
457 if (dict_find_string(op, "Function", &proc) <= 0) {
458 code = gs_note_error(e_rangecheck);
459 goto fail;
460 }
461 if (!r_is_proc(proc)) {
462 code = gs_note_error(e_typecheck);
463 goto fail;
464 }
465 size = 0;
466 code = check_psc_function(i_ctx_p, proc, 0, NULL, &size);
467 if (code < 0)
468 goto fail;
469 ops = gs_alloc_string(mem, size + 1, "gs_build_function_4(ops)");
470 if (ops == 0) {
471 code = gs_note_error(e_VMerror);
472 goto fail;
473 }
474 size = 0;
475 check_psc_function(i_ctx_p, proc, 0, ops, &size); /* can't fail */
476 ops[size] = PtCr_return;
477 params.ops.data = ops;
478 params.ops.size = size + 1;
479 code = gs_function_PtCr_init(ppfn, ¶ms, mem);
480 if (code >= 0)
481 return 0;
482 /* free_params will free the ops string */
483 fail:
484 gs_function_PtCr_free_params(¶ms, mem);
485 return (code < 0 ? code : gs_note_error(e_rangecheck));
486 }
487
make_type4_function(i_ctx_t * i_ctx_p,ref * arr,ref * pproc,gs_function_t ** func)488 int make_type4_function(i_ctx_t * i_ctx_p, ref *arr, ref *pproc, gs_function_t **func)
489 {
490 int code, size, num_components, CIESubst;
491 byte *ops;
492 gs_function_PtCr_params_t params;
493 float *ptr;
494 ref alternatespace, *palternatespace = &alternatespace;
495 PS_colour_space_t *space, *altspace;
496
497 code = get_space_object(i_ctx_p, arr, &space);
498 if (code < 0)
499 return code;
500 if (!space->alternateproc)
501 return e_typecheck;
502 code = space->alternateproc(i_ctx_p, arr, &palternatespace, &CIESubst);
503 if (code < 0)
504 return code;
505 code = get_space_object(i_ctx_p, palternatespace, &altspace);
506 if (code < 0)
507 return code;
508
509 code = space->numcomponents(i_ctx_p, arr, &num_components);
510 if (code < 0)
511 return code;
512 ptr = (float *)gs_alloc_byte_array(imemory, num_components * 2, sizeof(float), "make_type4_function(Domain)");
513 if (!ptr)
514 return e_VMerror;
515 code = space->domain(i_ctx_p, arr, ptr);
516 if (code < 0) {
517 gs_free_const_object(imemory, ptr, "make_type4_function(Domain)");
518 return code;
519 }
520 params.Domain = ptr;
521 params.m = num_components;
522
523 code = altspace->numcomponents(i_ctx_p, &alternatespace, &num_components);
524 if (code < 0) {
525 gs_free_const_object(imemory, params.Domain, "make_type4_function(Domain)");
526 return code;
527 }
528 ptr = (float *)gs_alloc_byte_array(imemory, num_components * 2, sizeof(float), "make_type4_function(Range)");
529 if (!ptr) {
530 gs_free_const_object(imemory, params.Domain, "make_type4_function(Domain)");
531 return e_VMerror;
532 }
533 code = altspace->range(i_ctx_p, &alternatespace, ptr);
534 if (code < 0) {
535 gs_free_const_object(imemory, ptr, "make_type4_function(Domain)");
536 gs_free_const_object(imemory, params.Domain, "make_type4_function(Range)");
537 return code;
538 }
539 params.Range = ptr;
540 params.n = num_components;
541
542 params.ops.data = 0; /* in case of failure, see gs_function_PtCr_free_params */
543 params.ops.size = 0; /* ditto */
544 size = 0;
545 code = check_psc_function(i_ctx_p, (const ref *)pproc, 0, NULL, &size);
546 if (code < 0) {
547 gs_function_PtCr_free_params(¶ms, imemory);
548 return code;
549 }
550 ops = gs_alloc_string(imemory, size + 1, "make_type4_function(ops)");
551 size = 0;
552 check_psc_function(i_ctx_p, (const ref *)pproc, 0, ops, &size); /* can't fail */
553 ops[size] = PtCr_return;
554 params.ops.data = ops;
555 params.ops.size = size + 1;
556 code = gs_function_PtCr_init(func, ¶ms, imemory);
557 if (code < 0)
558 gs_function_PtCr_free_params(¶ms, imemory);
559
560 return code;
561 }
562