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