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