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 *)&params = *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, &params, mem);
480     if (code >= 0)
481         return 0;
482     /* free_params will free the ops string */
483 fail:
484     gs_function_PtCr_free_params(&params, 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(&params, 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, &params, imemory);
557     if (code < 0)
558         gs_function_PtCr_free_params(&params, imemory);
559 
560     return code;
561 }
562