xref: /plan9/sys/src/cmd/gs/src/gsfunc4.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 2000, 2001 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: gsfunc4.c,v 1.18 2005/04/19 14:35:12 igor Exp $ */
18 /* Implementation of FunctionType 4 (PostScript Calculator) Functions */
19 #include "math_.h"
20 #include "memory_.h"
21 #include "gx.h"
22 #include "gserrors.h"
23 #include "gsdsrc.h"
24 #include "gsfunc4.h"
25 #include "gxfarith.h"
26 #include "gxfunc.h"
27 #include "stream.h"
28 #include "strimpl.h"
29 #include "sfilter.h"		/* for SubFileDecode */
30 #include "spprint.h"
31 #include "stream.h"
32 
33 typedef struct gs_function_PtCr_s {
34     gs_function_head_t head;
35     gs_function_PtCr_params_t params;
36     /* Define a bogus DataSource for get_function_info. */
37     gs_data_source_t data_source;
38 } gs_function_PtCr_t;
39 
40 /* GC descriptor */
41 private_st_function_PtCr();
42 
43 /* Define the maximum stack depth. */
44 #define MAX_VSTACK 100		/* per documentation */
45 
46 /* Define the structure of values on the stack. */
47 typedef enum {
48     CVT_NONE = 0,	/* empty stack slot */
49     CVT_BOOL,
50     CVT_INT,
51     CVT_FLOAT
52 } calc_value_type_t;
53 typedef struct calc_value_s {
54     calc_value_type_t type;
55     union {
56 	int i;			/* also used for Boolean */
57 	float f;
58     } value;
59 } calc_value_t;
60 
61 /* Store a float. */
62 private inline void
store_float(calc_value_t * vsp,floatp f)63 store_float(calc_value_t *vsp, floatp f)
64 {
65     vsp->value.f = f;
66     vsp->type = CVT_FLOAT;
67 }
68 
69 /*
70  * Define extended opcodes with typed operands.  We use the original
71  * opcodes for the floating-point case.
72  */
73 typedef enum {
74 
75 	/* Typed variants */
76 
77     PtCr_abs_int = PtCr_NUM_OPCODES,
78     PtCr_add_int,
79     PtCr_mul_int,
80     PtCr_neg_int,
81     PtCr_not_bool,		/* default is int */
82     PtCr_sub_int,
83     PtCr_eq_int,
84     PtCr_ge_int,
85     PtCr_gt_int,
86     PtCr_le_int,
87     PtCr_lt_int,
88     PtCr_ne_int,
89 
90 	/* Coerce and re-dispatch */
91 
92     PtCr_int_to_float,
93     PtCr_2nd_int_to_float,
94     PtCr_int2_to_float,
95 
96 	/* Miscellaneous */
97 
98     PtCr_no_op,
99     PtCr_typecheck
100 
101 } gs_PtCr_typed_opcode_t;
102 
103 /* Evaluate a PostScript Calculator function. */
104 private int
fn_PtCr_evaluate(const gs_function_t * pfn_common,const float * in,float * out)105 fn_PtCr_evaluate(const gs_function_t *pfn_common, const float *in, float *out)
106 {
107     const gs_function_PtCr_t *pfn = (const gs_function_PtCr_t *)pfn_common;
108     calc_value_t vstack_buf[2 + MAX_VSTACK + 1];
109     calc_value_t *vstack = &vstack_buf[1];
110     calc_value_t *vsp = vstack + pfn->params.m;
111     const byte *p = pfn->params.ops.data;
112     int i;
113 
114     /*
115      * Define the table for mapping explicit opcodes to typed opcodes.
116      * We index this table with the opcode and the types of the top 2
117      * values on the stack.
118      */
119     static const struct op_defn_s {
120 	byte opcode[16];	/* 4 * type[-1] + type[0] */
121     } op_defn_table[] = {
122 	/* Keep this consistent with opcodes in gsfunc4.h! */
123 
124 #define O4(op) op,op,op,op
125 #define E PtCr_typecheck
126 #define E4 O4(E)
127 #define N PtCr_no_op
128 	/* 0-operand operators */
129 #define OP_NONE(op)\
130   {{O4(op), O4(op), O4(op), O4(op)}}
131 	/* 1-operand operators */
132 #define OP1(b, i, f)\
133   {{E,b,i,f, E,b,i,f, E,b,i,f, E,b,i,f}}
134 #define OP_NUM1(i, f)\
135   OP1(E, i, f)
136 #define OP_MATH1(f)\
137   OP1(E, PtCr_int_to_float, f)
138 #define OP_ANY1(op)\
139   OP1(op, op, op)
140 	/* 2-operand operators */
141 #define OP_NUM2(i, f)\
142   {{E4, E4, E,E,i,PtCr_2nd_int_to_float, E,E,PtCr_int_to_float,f}}
143 #define OP_INT_BOOL2(i)\
144   {{E4, E,i,i,E, E,i,i,E, E4}}
145 #define OP_MATH2(f)\
146   {{E4, E4, E,E,PtCr_int2_to_float,PtCr_2nd_int_to_float,\
147     E,E,PtCr_int_to_float,f}}
148 #define OP_INT2(i)\
149   {{E4, E4, E,E,i,E, E4}}
150 #define OP_REL2(i, f)\
151   {{E4, E,i,E,E, E,E,i,PtCr_2nd_int_to_float, E,E,PtCr_int_to_float,f}}
152 #define OP_ANY2(op)\
153   {{E4, E,op,op,op, E,op,op,op, E,op,op,op}}
154 
155     /* Arithmetic operators */
156 
157 	OP_NUM1(PtCr_abs_int, PtCr_abs),	/* abs */
158 	OP_NUM2(PtCr_add_int, PtCr_add),	/* add */
159 	OP_INT_BOOL2(PtCr_and),  /* and */
160 	OP_MATH2(PtCr_atan),	/* atan */
161 	OP_INT2(PtCr_bitshift),	/* bitshift */
162 	OP_NUM1(N, PtCr_ceiling),	/* ceiling */
163 	OP_MATH1(PtCr_cos),	/* cos */
164 	OP_NUM1(N, PtCr_cvi),	/* cvi */
165 	OP_NUM1(PtCr_int_to_float, N),	/* cvr */
166 	OP_MATH2(PtCr_div),	/* div */
167 	OP_MATH2(PtCr_exp),	/* exp */
168 	OP_NUM1(N, PtCr_floor),	/* floor */
169 	OP_INT2(PtCr_idiv),	/* idiv */
170 	OP_MATH1(PtCr_ln),	/* ln */
171 	OP_MATH1(PtCr_log),	/* log */
172 	OP_INT2(PtCr_mod),	/* mod */
173 	OP_NUM2(PtCr_mul_int, PtCr_mul),	/* mul */
174 	OP_NUM1(PtCr_neg_int, PtCr_neg),	/* neg */
175 	OP1(PtCr_not, PtCr_not, E),	/* not */
176 	OP_INT_BOOL2(PtCr_or),  /* or */
177 	OP_NUM1(N, PtCr_round),	/* round */
178 	OP_MATH1(PtCr_sin),	/* sin */
179 	OP_MATH1(PtCr_sqrt),	/* sqrt */
180 	OP_NUM2(PtCr_sub_int, PtCr_sub),	/* sub */
181 	OP_NUM1(N, PtCr_truncate),	/* truncate */
182 	OP_INT_BOOL2(PtCr_xor),  /* xor */
183 
184     /* Comparison operators */
185 
186 	OP_REL2(PtCr_eq_int, PtCr_eq),	/* eq */
187 	OP_NUM2(PtCr_ge_int, PtCr_ge),	/* ge */
188 	OP_NUM2(PtCr_gt_int, PtCr_gt),	/* gt */
189 	OP_NUM2(PtCr_le_int, PtCr_le),	/* le */
190 	OP_NUM2(PtCr_lt_int, PtCr_lt),	/* lt */
191 	OP_REL2(PtCr_ne_int, PtCr_ne),	/* ne */
192 
193     /* Stack operators */
194 
195 	OP1(E, PtCr_copy, E),	/* copy */
196 	OP_ANY1(PtCr_dup),	/* dup */
197 	OP_ANY2(PtCr_exch),	/* exch */
198 	OP1(E, PtCr_index, E),	/* index */
199 	OP_ANY1(PtCr_pop),	/* pop */
200 	OP_INT2(PtCr_roll),	/* roll */
201 
202     /* Constants */
203 
204 	OP_NONE(PtCr_byte),		/* byte */
205 	OP_NONE(PtCr_int),		/* int */
206 	OP_NONE(PtCr_float),		/* float */
207 	OP_NONE(PtCr_true),		/* true */
208 	OP_NONE(PtCr_false),		/* false */
209 
210     /* Special */
211 
212 	OP1(PtCr_if, E, E),		/* if */
213 	OP_NONE(PtCr_else),		/* else */
214 	OP_NONE(PtCr_return)		/* return */
215 
216     };
217 
218     vstack[-1].type = CVT_NONE;  /* for type dispatch in empty stack case */
219     vstack[0].type = CVT_NONE;	/* catch underflow */
220     for (i = 0; i < pfn->params.m; ++i)
221 	store_float(&vstack[i + 1], in[i]);
222 
223     for (; ; ) {
224 	int code, n;
225 
226     sw:
227 	switch (op_defn_table[*p++].opcode[(vsp[-1].type << 2) + vsp->type]) {
228 
229 	    /* Miscellaneous */
230 
231 	case PtCr_no_op:
232 	    continue;
233 	case PtCr_typecheck:
234 	    return_error(gs_error_typecheck);
235 
236 	    /* Coerce and re-dispatch */
237 
238 	case PtCr_int_to_float:
239 	    store_float(vsp, (floatp)vsp->value.i);
240 	    --p; goto sw;
241 	case PtCr_int2_to_float:
242 	    store_float(vsp, (floatp)vsp->value.i);
243 	case PtCr_2nd_int_to_float:
244 	    store_float(vsp - 1, (floatp)vsp[-1].value.i);
245 	    --p; goto sw;
246 
247 	    /* Arithmetic operators */
248 
249 	case PtCr_abs_int:
250 	    if (vsp->value.i < 0)
251 		goto neg_int;
252 	    continue;
253 	case PtCr_abs:
254 	    vsp->value.f = fabs(vsp->value.f);
255 	    continue;
256 	case PtCr_add_int: {
257 	    int int1 = vsp[-1].value.i, int2 = vsp->value.i;
258 
259 	    if ((int1 ^ int2) >= 0 && ((int1 + int2) ^ int1) < 0)
260 		store_float(vsp - 1, (double)int1 + int2);
261 	    else
262 		vsp[-1].value.i = int1 + int2;
263 	    --vsp; continue;
264 	}
265 	case PtCr_add:
266 	    vsp[-1].value.f += vsp->value.f;
267 	    --vsp; continue;
268 	case PtCr_and:
269 	    vsp[-1].value.i &= vsp->value.i;
270 	    --vsp; continue;
271 	case PtCr_atan: {
272 	    double result;
273 
274 	    code = gs_atan2_degrees(vsp[-1].value.f, vsp->value.f,
275 				    &result);
276 	    if (code < 0)
277 		return code;
278 	    vsp[-1].value.f = result;
279 	    --vsp; continue;
280 	}
281 	case PtCr_bitshift:
282 #define MAX_SHIFT (ARCH_SIZEOF_INT * 8 - 1)
283 	    if (vsp->value.i < -MAX_SHIFT || vsp->value.i > MAX_SHIFT)
284 		vsp[-1].value.i = 0;
285 #undef MAX_SHIFT
286 	    else if ((n = vsp->value.i) < 0)
287 		vsp[-1].value.i = ((uint)(vsp[-1].value.i)) >> -n;
288 	    else
289 		vsp[-1].value.i <<= n;
290 	    --vsp; continue;
291 	case PtCr_ceiling:
292 	    vsp->value.f = ceil(vsp->value.f);
293 	    continue;
294 	case PtCr_cos:
295 	    vsp->value.f = gs_cos_degrees(vsp->value.f);
296 	    continue;
297 	case PtCr_cvi:
298 	    vsp->value.i = (int)(vsp->value.f);
299 	    vsp->type = CVT_INT;
300 	    continue;
301 	case PtCr_cvr:
302 	    continue;	/* prepare handled it */
303 	case PtCr_div:
304 	    if (vsp->value.f == 0)
305 		return_error(gs_error_undefinedresult);
306 	    vsp[-1].value.f /= vsp->value.f;
307 	    --vsp; continue;
308 	case PtCr_exp:
309 	    vsp[-1].value.f = pow(vsp[-1].value.f, vsp->value.f);
310 	    --vsp; continue;
311 	case PtCr_floor:
312 	    vsp->value.f = floor(vsp->value.f);
313 	    continue;
314 	case PtCr_idiv:
315 	    if (vsp->value.i == 0)
316 		return_error(gs_error_undefinedresult);
317 	    if ((vsp[-1].value.i /= vsp->value.i) == min_int &&
318 		vsp->value.i == -1)  /* anomalous boundary case, fail */
319 		return_error(gs_error_rangecheck);
320 	    --vsp; continue;
321 	case PtCr_ln:
322 	    vsp->value.f = log(vsp->value.f);
323 	    continue;
324 	case PtCr_log:
325 	    vsp->value.f = log10(vsp->value.f);
326 	    continue;
327 	case PtCr_mod:
328 	    if (vsp->value.i == 0)
329 		return_error(gs_error_undefinedresult);
330 	    vsp[-1].value.i %= vsp->value.i;
331 	    --vsp; continue;
332 	case PtCr_mul_int: {
333 	    /* We don't bother to optimize this. */
334 	    double prod = (double)vsp[-1].value.i * vsp->value.i;
335 
336 	    if (prod < min_int || prod > max_int)
337 		store_float(vsp - 1, prod);
338 	    else
339 		vsp[-1].value.i = (int)prod;
340 	    --vsp; continue;
341 	}
342 	case PtCr_mul:
343 	    vsp[-1].value.f *= vsp->value.f;
344 	    --vsp; continue;
345 	case PtCr_neg_int:
346 	neg_int:
347 	    if (vsp->value.i == min_int)
348 		store_float(vsp, (floatp)vsp->value.i); /* =self negated */
349 	    else
350 		vsp->value.i = -vsp->value.i;
351 	    continue;
352 	case PtCr_neg:
353 	    vsp->value.f = -vsp->value.f;
354 	    continue;
355 	case PtCr_not_bool:
356 	    vsp->value.i = !vsp->value.i;
357 	    continue;
358 	case PtCr_not:
359 	    vsp->value.i = ~vsp->value.i;
360 	    continue;
361 	case PtCr_or:
362 	    vsp[-1].value.i |= vsp->value.i;
363 	    --vsp; continue;
364 	case PtCr_round:
365 	    vsp->value.f = floor(vsp->value.f + 0.5);
366 	    continue;
367 	case PtCr_sin:
368 	    vsp->value.f = gs_sin_degrees(vsp->value.f);
369 	    continue;
370 	case PtCr_sqrt:
371 	    vsp->value.f = sqrt(vsp->value.f);
372 	    continue;
373 	case PtCr_sub_int: {
374 	    int int1 = vsp[-1].value.i, int2 = vsp->value.i;
375 
376 	    if ((int1 ^ int2) < 0 && ((int1 - int2) ^ int1) >= 0)
377 		store_float(vsp - 1, (double)int1 - int2);
378 	    else
379 		vsp[-1].value.i = int1 - int2;
380 	    --vsp; continue;
381 	}
382 	case PtCr_sub:
383 	    vsp[-1].value.f -= vsp->value.f;
384 	    --vsp; continue;
385 	case PtCr_truncate:
386 	    vsp->value.f = (vsp->value.f < 0 ? ceil(vsp->value.f) :
387 			    floor(vsp->value.f));
388 	    continue;
389 	case PtCr_xor:
390 	    vsp[-1].value.i ^= vsp->value.i;
391 	    --vsp; continue;
392 
393 	    /* Boolean operators */
394 
395 #define DO_REL(rel, m)\
396   vsp[-1].value.i = vsp[-1].value.m rel vsp->value.m
397 
398 	case PtCr_eq_int:
399 	    DO_REL(==, i);
400 	    goto rel;
401 	case PtCr_eq:
402 	    DO_REL(==, f);
403 	rel:
404 	    vsp[-1].type = CVT_BOOL;
405 	    --vsp; continue;
406 	case PtCr_ge_int:
407 	    DO_REL(>=, i);
408 	    goto rel;
409 	case PtCr_ge:
410 	    DO_REL(>=, f);
411 	    goto rel;
412 	case PtCr_gt_int:
413 	    DO_REL(>, i);
414 	    goto rel;
415 	case PtCr_gt:
416 	    DO_REL(>, f);
417 	    goto rel;
418 	case PtCr_le_int:
419 	    DO_REL(<=, i);
420 	    goto rel;
421 	case PtCr_le:
422 	    DO_REL(<=, f);
423 	    goto rel;
424 	case PtCr_lt_int:
425 	    DO_REL(<, i);
426 	    goto rel;
427 	case PtCr_lt:
428 	    DO_REL(<, f);
429 	    goto rel;
430 	case PtCr_ne_int:
431 	    DO_REL(!=, i);
432 	    goto rel;
433 	case PtCr_ne:
434 	    DO_REL(!=, f);
435 	    goto rel;
436 
437 #undef DO_REL
438 
439 	    /* Stack operators */
440 
441 	case PtCr_copy:
442 	    i = vsp->value.i;
443 	    n = vsp - vstack;
444 	    if (i < 0 || i >= n)
445 		return_error(gs_error_rangecheck);
446 	    if (i > MAX_VSTACK - (n - 1))
447 		return_error(gs_error_limitcheck);
448 	    memcpy(vsp, vsp - i, i * sizeof(*vsp));
449 	    vsp += i - 1;
450 	    continue;
451 	case PtCr_dup:
452 	    vsp[1] = *vsp;
453 	    goto push;
454 	case PtCr_exch:
455 	    vstack[MAX_VSTACK] = *vsp;
456 	    *vsp = vsp[-1];
457 	    vsp[-1] = vstack[MAX_VSTACK];
458 	    continue;
459 	case PtCr_index:
460 	    i = vsp->value.i;
461 	    if (i < 0 || i >= vsp - vstack - 1)
462 		return_error(gs_error_rangecheck);
463 	    *vsp = vsp[-i - 1];
464 	    continue;
465 	case PtCr_pop:
466 	    --vsp;
467 	    continue;
468 	case PtCr_roll:
469 	    n = vsp[-1].value.i;
470 	    i = vsp->value.i;
471 	    if (n < 0 || n > vsp - vstack - 2)
472 		return_error(gs_error_rangecheck);
473 	    /* We don't bother to do this efficiently. */
474 	    for (; i > 0; i--) {
475 		memmove(vsp - n, vsp - (n + 1), n * sizeof(*vsp));
476 		vsp[-(n + 1)] = vsp[-1];
477 	    }
478 	    for (; i < 0; i++) {
479 		vsp[-1] = vsp[-(n + 1)];
480 		memmove(vsp - (n + 1), vsp - n, n * sizeof(*vsp));
481 	    }
482 	    vsp -= 2;
483 	    continue;
484 
485 	    /* Constants */
486 
487 	case PtCr_byte:
488 	    vsp[1].value.i = *p++, vsp[1].type = CVT_INT;
489 	    goto push;
490 	case PtCr_int /* native */:
491 	    memcpy(&vsp[1].value.i, p, sizeof(int));
492 	    vsp[1].type = CVT_INT;
493 	    p += sizeof(int);
494 	    goto push;
495 	case PtCr_float /* native */:
496 	    memcpy(&vsp[1].value.f, p, sizeof(float));
497 	    vsp[1].type = CVT_FLOAT;
498 	    p += sizeof(float);
499 	    goto push;
500 	case PtCr_true:
501 	    vsp[1].value.i = true, vsp[1].type = CVT_BOOL;
502 	    goto push;
503 	case PtCr_false:
504 	    vsp[1].value.i = false, vsp[1].type = CVT_BOOL;
505 	push:
506 	    if (vsp == &vstack[MAX_VSTACK])
507 		return_error(gs_error_limitcheck);
508 	    ++vsp;
509 	    continue;
510 
511 	    /* Special */
512 
513 	case PtCr_if:
514 	    if ((vsp--)->value.i) {	/* value is true, execute body */
515 		p += 2;
516 		continue;
517 	    }
518 	    /* falls through */
519 	case PtCr_else:
520 	    p += 2 + (p[0] << 8) + p[1];
521 	    continue;
522 	case PtCr_return:
523 	    goto fin;
524 	}
525     }
526  fin:
527 
528     if (vsp != vstack + pfn->params.n)
529 	return_error(gs_error_rangecheck);
530     for (i = 0; i < pfn->params.n; ++i) {
531 	switch (vstack[i + 1].type) {
532 	case CVT_INT:
533 	    out[i] = (float)vstack[i + 1].value.i;
534 	    break;
535 	case CVT_FLOAT:
536 	    out[i] = vstack[i + 1].value.f;
537 	    break;
538 	default:
539 	    return_error(gs_error_typecheck);
540 	}
541     }
542     return 0;
543 }
544 
545 /* Test whether a PostScript Calculator function is monotonic. */
546 private int
fn_PtCr_is_monotonic(const gs_function_t * pfn_common,const float * lower,const float * upper,uint * mask)547 fn_PtCr_is_monotonic(const gs_function_t * pfn_common,
548 		     const float *lower, const float *upper, uint *mask)
549 {
550     /*
551      * No reasonable way to tell.  Eventually we should check for
552      * functions consisting of only stack-manipulating operations,
553      * since these may be common for DeviceN color spaces and *are*
554      * monotonic.
555      */
556     *mask = 0x49249249;
557     return 0;
558 }
559 
560 /* Write the function definition in symbolic form on a stream. */
561 private int
calc_put_ops(stream * s,const byte * ops,uint size)562 calc_put_ops(stream *s, const byte *ops, uint size)
563 {
564     const byte *p;
565 
566     spputc(s, '{');
567     for (p = ops; p < ops + size; )
568 	switch (*p++) {
569 	case PtCr_byte:
570 	    pprintd1(s, "%d ", *p++);
571 	    break;
572 	case PtCr_int: {
573 	    int i;
574 
575 	    memcpy(&i, p, sizeof(int));
576 	    pprintd1(s, "%d ", i);
577 	    p += sizeof(int);
578 	    break;
579 	}
580 	case PtCr_float: {
581 	    float f;
582 
583 	    memcpy(&f, p, sizeof(float));
584 	    pprintg1(s, "%g ", f);
585 	    p += sizeof(float);
586 	    break;
587 	}
588 	case PtCr_true:
589 	    stream_puts(s, "true ");
590 	    break;
591 	case PtCr_false:
592 	    stream_puts(s, "false ");
593 	    break;
594 	case PtCr_if: {
595 	    int skip = (p[0] << 8) + p[1];
596 	    int code;
597 
598 	    code = calc_put_ops(s, p += 2, skip);
599 	    p += skip;
600 	    if (code < 0)
601 		return code;
602 	    if (code > 0) {	/* else */
603 		skip = (p[-2] << 8) + p[-1];
604 		code = calc_put_ops(s, p, skip);
605 		p += skip;
606 		if (code < 0)
607 		    return code;
608 		stream_puts(s, " ifelse ");
609 	    } else
610 		stream_puts(s, " if ");
611 	    break;
612 	}
613 	case PtCr_else:
614 	    if (p != ops + size - 2)
615 		return_error(gs_error_rangecheck);
616 	    spputc(s, '}');
617 	    return 1;
618 	/*case PtCr_return:*/	/* not possible */
619 	default: {		/* must be < PtCr_NUM_OPS */
620 		static const char *const op_names[] = {
621 		    /* Keep this consistent with opcodes in gsfunc4.h! */
622 		    "abs", "add", "and", "atan", "bitshift",
623 		    "ceiling", "cos", "cvi", "cvr", "div", "exp",
624 		    "floor", "idiv", "ln", "log", "mod", "mul",
625 		    "neg", "not", "or", "round", "sin", "sqrt", "sub",
626 		    "truncate", "xor",
627 		    "eq", "ge", "gt", "le", "lt", "ne",
628 		    "copy", "dup", "exch", "index", "pop", "roll"
629 		};
630 
631 		pprints1(s, "%s ", op_names[p[-1]]);
632 	    }
633 	}
634     spputc(s, '}');
635     return 0;
636 }
637 private int
calc_put(stream * s,const gs_function_PtCr_t * pfn)638 calc_put(stream *s, const gs_function_PtCr_t *pfn)
639 {
640     calc_put_ops(s, pfn->params.ops.data, pfn->params.ops.size - 1);
641     return 0;
642 }
643 
644 /* Access the symbolic definition as a DataSource. */
645 private int
calc_access(const gs_data_source_t * psrc,ulong start,uint length,byte * buf,const byte ** ptr)646 calc_access(const gs_data_source_t *psrc, ulong start, uint length,
647 	    byte *buf, const byte **ptr)
648 {
649     const gs_function_PtCr_t *const pfn =
650 	(const gs_function_PtCr_t *)
651 	  ((const char *)psrc - offset_of(gs_function_PtCr_t, data_source));
652     /*
653      * The caller wants a specific substring of the symbolic definition.
654      * Generate the entire definition, using a SubFileDecode filter (in an
655      * output pipeline!) to extract the substring.  This is very
656      * inefficient, but this code is rarely used, and almost never actually
657      * has to break up the definition into pieces to fit in the caller's
658      * buffer.
659      */
660     stream_SFD_state st;
661     stream ds, bs;
662     byte dbuf[200];		/* arbitrary */
663     const stream_template *const template = &s_SFD_template;
664 
665     /* Set up the stream that writes into the buffer. */
666     s_init(&bs, NULL);
667     swrite_string(&bs, buf, length);
668     /* Set up the SubFileDecode stream. */
669     s_init(&ds, NULL);
670     s_init_state((stream_state *)&st, template, NULL);
671     template->set_defaults((stream_state *)&st);
672     st.skip_count = start;
673     s_init_filter(&ds, (stream_state *)&st, dbuf, sizeof(dbuf), &bs);
674     calc_put(&ds, pfn);
675     sclose(&ds);
676     if (ptr)
677 	*ptr = buf;
678     return 0;
679 }
680 
681 /* Return PostScript Calculator function information. */
682 private void
fn_PtCr_get_info(const gs_function_t * pfn_common,gs_function_info_t * pfi)683 fn_PtCr_get_info(const gs_function_t *pfn_common, gs_function_info_t *pfi)
684 {
685     const gs_function_PtCr_t *const pfn =
686 	(const gs_function_PtCr_t *)pfn_common;
687 
688     gs_function_get_info_default(pfn_common, pfi);
689     pfi->DataSource = &pfn->data_source;
690     {
691 	stream s;
692 
693 	s_init(&s, NULL);
694 	swrite_position_only(&s);
695 	calc_put(&s, pfn);
696 	pfi->data_size = stell(&s);
697     }
698 }
699 
700 /* Make a scaled copy of a PostScript Calculator function. */
701 private int
fn_PtCr_make_scaled(const gs_function_PtCr_t * pfn,gs_function_PtCr_t ** ppsfn,const gs_range_t * pranges,gs_memory_t * mem)702 fn_PtCr_make_scaled(const gs_function_PtCr_t *pfn, gs_function_PtCr_t **ppsfn,
703 		    const gs_range_t *pranges, gs_memory_t *mem)
704 {
705     gs_function_PtCr_t *psfn =
706 	gs_alloc_struct(mem, gs_function_PtCr_t, &st_function_PtCr,
707 			"fn_PtCr_make_scaled");
708     /* We are adding {<int> 1 roll <float> mul <float> add} for each output. */
709     int n = pfn->params.n;
710     uint opsize = pfn->params.ops.size + (9 + 2 * sizeof(float)) * n;
711     byte *ops = gs_alloc_string(mem, opsize, "fn_PtCr_make_scaled(ops)");
712     byte *p;
713     int code, i;
714 
715     if (psfn == 0 || ops == 0) {
716 	gs_free_string(mem, ops, opsize, "fn_PtCr_make_scaled(ops)");
717 	gs_free_object(mem, psfn, "fn_PtCr_make_scaled");
718 	return_error(gs_error_VMerror);
719     }
720     psfn->params = pfn->params;
721     psfn->params.ops.data = ops;
722     psfn->params.ops.size = opsize;
723     psfn->data_source = pfn->data_source;
724     code = fn_common_scale((gs_function_t *)psfn, (const gs_function_t *)pfn,
725 			   pranges, mem);
726     if (code < 0) {
727 	gs_function_free((gs_function_t *)psfn, true, mem);
728 	return code;
729     }
730     memcpy(ops, pfn->params.ops.data, pfn->params.ops.size - 1); /* minus return */
731     p = ops + pfn->params.ops.size - 1;
732     for (i = n; --i >= 0; ) {
733 	float base = pranges[i].rmin;
734 	float factor = pranges[i].rmax - base;
735 
736 	if (factor != 1) {
737 	    p[0] = PtCr_float; memcpy(p + 1, &factor, sizeof(float));
738 	    p += 1 + sizeof(float);
739 	    *p++ = PtCr_mul;
740 	}
741 	if (base != 0) {
742 	    p[0] = PtCr_float; memcpy(p + 1, &base, sizeof(float));
743 	    p += 1 + sizeof(float);
744 	    *p++ = PtCr_add;
745 	}
746 	if (n != 1) {
747 	    p[0] = PtCr_byte; p[1] = (byte)n;
748 	    p[2] = PtCr_byte; p[3] = 1;
749 	    p[4] = PtCr_roll;
750 	    p += 5;
751 	}
752     }
753     *p++ = PtCr_return;
754     psfn->params.ops.size = p - ops;
755     psfn->params.ops.data =
756 	gs_resize_string(mem, ops, opsize, psfn->params.ops.size,
757 			 "fn_PtCr_make_scaled");
758     *ppsfn = psfn;
759     return 0;
760 }
761 
762 
763 /* Free the parameters of a PostScript Calculator function. */
764 void
gs_function_PtCr_free_params(gs_function_PtCr_params_t * params,gs_memory_t * mem)765 gs_function_PtCr_free_params(gs_function_PtCr_params_t * params, gs_memory_t * mem)
766 {
767     gs_free_const_string(mem, params->ops.data, params->ops.size, "ops");
768     fn_common_free_params((gs_function_params_t *) params, mem);
769 }
770 
771 /* Serialize. */
772 private int
gs_function_PtCr_serialize(const gs_function_t * pfn,stream * s)773 gs_function_PtCr_serialize(const gs_function_t * pfn, stream *s)
774 {
775     uint n;
776     const gs_function_PtCr_params_t * p = (const gs_function_PtCr_params_t *)&pfn->params;
777     int code = fn_common_serialize(pfn, s);
778 
779     if (code < 0)
780 	return code;
781     code = sputs(s, (const byte *)&p->ops.size, sizeof(p->ops.size), &n);
782     if (code < 0)
783 	return code;
784     return sputs(s, p->ops.data, p->ops.size, &n);
785 }
786 
787 /* Allocate and initialize a PostScript Calculator function. */
788 int
gs_function_PtCr_init(gs_function_t ** ppfn,const gs_function_PtCr_params_t * params,gs_memory_t * mem)789 gs_function_PtCr_init(gs_function_t ** ppfn,
790 		  const gs_function_PtCr_params_t * params, gs_memory_t * mem)
791 {
792     static const gs_function_head_t function_PtCr_head = {
793 	function_type_PostScript_Calculator,
794 	{
795 	    (fn_evaluate_proc_t) fn_PtCr_evaluate,
796 	    (fn_is_monotonic_proc_t) fn_PtCr_is_monotonic,
797 	    (fn_get_info_proc_t) fn_PtCr_get_info,
798 	    fn_common_get_params,
799 	    (fn_make_scaled_proc_t) fn_PtCr_make_scaled,
800 	    (fn_free_params_proc_t) gs_function_PtCr_free_params,
801 	    fn_common_free,
802 	    (fn_serialize_proc_t) gs_function_PtCr_serialize,
803 	}
804     };
805     int code;
806 
807     *ppfn = 0;			/* in case of error */
808     code = fn_check_mnDR((const gs_function_params_t *)params,
809 			 params->m, params->n);
810     if (code < 0)
811 	return code;
812     if (params->m > MAX_VSTACK || params->n > MAX_VSTACK)
813 	return_error(gs_error_limitcheck);
814     /*
815      * Pre-validate the operation string to reduce evaluation overhead.
816      */
817     {
818 	const byte *p = params->ops.data;
819 
820 	for (; *p != PtCr_return; ++p)
821 	    switch ((gs_PtCr_opcode_t)*p) {
822 	    case PtCr_byte:
823 		++p; break;
824 	    case PtCr_int:
825 		p += sizeof(int); break;
826 	    case PtCr_float:
827 		p += sizeof(float); break;
828 	    case PtCr_if:
829 	    case PtCr_else:
830 		p += 2;
831 	    case PtCr_true:
832 	    case PtCr_false:
833 		break;
834 	    default:
835 		if (*p >= PtCr_NUM_OPS)
836 		    return_error(gs_error_rangecheck);
837 	    }
838 	if (p != params->ops.data + params->ops.size - 1)
839 	    return_error(gs_error_rangecheck);
840     }
841     {
842 	gs_function_PtCr_t *pfn =
843 	    gs_alloc_struct(mem, gs_function_PtCr_t, &st_function_PtCr,
844 			    "gs_function_PtCr_init");
845 
846 	if (pfn == 0)
847 	    return_error(gs_error_VMerror);
848 	pfn->params = *params;
849 	/*
850 	 * We claim to have a DataSource, in order to write the function
851 	 * definition in symbolic form for embedding in PDF files.
852 	 * ****** THIS IS A HACK. ******
853 	 */
854 	data_source_init_string2(&pfn->data_source, NULL, 0);
855 	pfn->data_source.access = calc_access;
856 	pfn->head = function_PtCr_head;
857 	*ppfn = (gs_function_t *) pfn;
858     }
859     return 0;
860 }
861