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