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