/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 | 116M | #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 | 58.2M | { |
67 | 58.2M | vsp->value.f = f; |
68 | 58.2M | vsp->type = CVT_FLOAT; |
69 | 58.2M | } |
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 | 11.6M | { |
109 | 11.6M | const gs_function_PtCr_t *pfn = (const gs_function_PtCr_t *)pfn_common; |
110 | 11.6M | calc_value_t vstack_buf[2 + MAX_VSTACK + 1]; |
111 | 11.6M | calc_value_t *vstack = &vstack_buf[1]; |
112 | 11.6M | calc_value_t *vsp = vstack + pfn->params.m; |
113 | 11.6M | const byte *p = pfn->params.ops.data; |
114 | 11.6M | int repeat_count[MAX_PSC_FUNCTION_NESTING]; |
115 | 11.6M | int repeat_proc_size[MAX_PSC_FUNCTION_NESTING]; |
116 | 11.6M | int repeat_nesting_level = -1; |
117 | 11.6M | 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 | 11.6M | static const struct op_defn_s { |
125 | 11.6M | byte opcode[16]; /* 4 * type[-1] + type[0] */ |
126 | 11.6M | } op_defn_table[] = { |
127 | | /* Keep this consistent with opcodes in gsfunc4.h! */ |
128 | | |
129 | 848M | #define O4(op) op,op,op,op |
130 | 1.87G | #define E PtCr_typecheck |
131 | 476M | #define E4 O4(E) |
132 | 11.6M | #define N PtCr_no_op |
133 | | /* 0-operand operators */ |
134 | 11.6M | #define OP_NONE(op)\ |
135 | 93.0M | {{O4(op), O4(op), O4(op), O4(op)}} |
136 | | /* 1-operand operators */ |
137 | 11.6M | #define OP1(b, i, f)\ |
138 | 232M | {{E,b,i,f, E,b,i,f, E,b,i,f, E,b,i,f}} |
139 | 11.6M | #define OP_NUM1(i, f)\ |
140 | 93.0M | OP1(E, i, f) |
141 | 11.6M | #define OP_MATH1(f)\ |
142 | 58.1M | OP1(E, PtCr_int_to_float, f) |
143 | 11.6M | #define OP_ANY1(op)\ |
144 | 23.2M | OP1(op, op, op) |
145 | | /* 2-operand operators */ |
146 | 11.6M | #define OP_NUM2(i, f)\ |
147 | 81.3M | {{E4, E4, E,E,i,PtCr_2nd_int_to_float, E,E,PtCr_int_to_float,f}} |
148 | 11.6M | #define OP_INT_BOOL2(i)\ |
149 | 34.8M | {{E4, E,i,i,E, E,i,i,E, E4}} |
150 | 11.6M | #define OP_MATH2(f)\ |
151 | 34.8M | {{E4, E4, E,E,PtCr_int2_to_float,PtCr_2nd_int_to_float,\ |
152 | 34.8M | E,E,PtCr_int_to_float,f}} |
153 | 11.6M | #define OP_INT2(i)\ |
154 | 46.5M | {{E4, E4, E,E,i,E, E4}} |
155 | 11.6M | #define OP_REL2(i, f)\ |
156 | 23.2M | {{E4, E,i,E,E, E,E,i,PtCr_2nd_int_to_float, E,E,PtCr_int_to_float,f}} |
157 | 11.6M | #define OP_ANY2(op)\ |
158 | 11.6M | {{E4, E,op,op,op, E,op,op,op, E,op,op,op}} |
159 | | |
160 | | /* Arithmetic operators */ |
161 | | |
162 | 11.6M | OP_NUM1(PtCr_abs_int, PtCr_abs), /* abs */ |
163 | 11.6M | OP_NUM2(PtCr_add_int, PtCr_add), /* add */ |
164 | 11.6M | OP_INT_BOOL2(PtCr_and), /* and */ |
165 | 11.6M | OP_MATH2(PtCr_atan), /* atan */ |
166 | 11.6M | OP_INT2(PtCr_bitshift), /* bitshift */ |
167 | 11.6M | OP_NUM1(N, PtCr_ceiling), /* ceiling */ |
168 | 11.6M | OP_MATH1(PtCr_cos), /* cos */ |
169 | 11.6M | OP_NUM1(N, PtCr_cvi), /* cvi */ |
170 | 11.6M | OP_NUM1(PtCr_int_to_float, N), /* cvr */ |
171 | 11.6M | OP_MATH2(PtCr_div), /* div */ |
172 | 11.6M | OP_MATH2(PtCr_exp), /* exp */ |
173 | 11.6M | OP_NUM1(N, PtCr_floor), /* floor */ |
174 | 11.6M | OP_INT2(PtCr_idiv), /* idiv */ |
175 | 11.6M | OP_MATH1(PtCr_ln), /* ln */ |
176 | 11.6M | OP_MATH1(PtCr_log), /* log */ |
177 | 11.6M | OP_INT2(PtCr_mod), /* mod */ |
178 | 11.6M | OP_NUM2(PtCr_mul_int, PtCr_mul), /* mul */ |
179 | 11.6M | OP_NUM1(PtCr_neg_int, PtCr_neg), /* neg */ |
180 | 11.6M | OP1(PtCr_not, PtCr_not, E), /* not */ |
181 | 11.6M | OP_INT_BOOL2(PtCr_or), /* or */ |
182 | 11.6M | OP_NUM1(N, PtCr_round), /* round */ |
183 | 11.6M | OP_MATH1(PtCr_sin), /* sin */ |
184 | 11.6M | OP_MATH1(PtCr_sqrt), /* sqrt */ |
185 | 11.6M | OP_NUM2(PtCr_sub_int, PtCr_sub), /* sub */ |
186 | 11.6M | OP_NUM1(N, PtCr_truncate), /* truncate */ |
187 | 11.6M | OP_INT_BOOL2(PtCr_xor), /* xor */ |
188 | | |
189 | | /* Comparison operators */ |
190 | | |
191 | 11.6M | OP_REL2(PtCr_eq_int, PtCr_eq), /* eq */ |
192 | 11.6M | OP_NUM2(PtCr_ge_int, PtCr_ge), /* ge */ |
193 | 11.6M | OP_NUM2(PtCr_gt_int, PtCr_gt), /* gt */ |
194 | 11.6M | OP_NUM2(PtCr_le_int, PtCr_le), /* le */ |
195 | 11.6M | OP_NUM2(PtCr_lt_int, PtCr_lt), /* lt */ |
196 | 11.6M | OP_REL2(PtCr_ne_int, PtCr_ne), /* ne */ |
197 | | |
198 | | /* Stack operators */ |
199 | | |
200 | 11.6M | OP1(E, PtCr_copy, E), /* copy */ |
201 | 11.6M | OP_ANY1(PtCr_dup), /* dup */ |
202 | 11.6M | OP_ANY2(PtCr_exch), /* exch */ |
203 | 11.6M | OP1(E, PtCr_index, E), /* index */ |
204 | 11.6M | OP_ANY1(PtCr_pop), /* pop */ |
205 | 11.6M | OP_INT2(PtCr_roll), /* roll */ |
206 | | |
207 | | /* Constants */ |
208 | | |
209 | 11.6M | OP_NONE(PtCr_byte), /* byte */ |
210 | 11.6M | OP_NONE(PtCr_int), /* int */ |
211 | 11.6M | OP_NONE(PtCr_float), /* float */ |
212 | 11.6M | OP_NONE(PtCr_true), /* true */ |
213 | 11.6M | OP_NONE(PtCr_false), /* false */ |
214 | | |
215 | | /* Special */ |
216 | | |
217 | 11.6M | OP1(PtCr_if, E, E), /* if */ |
218 | 11.6M | OP_NONE(PtCr_else), /* else */ |
219 | 11.6M | OP_NONE(PtCr_return), /* return */ |
220 | 11.6M | OP1(E, PtCr_repeat, E), /* repeat */ |
221 | 11.6M | OP_NONE(PtCr_repeat_end) /* repeat_end */ |
222 | 11.6M | }; |
223 | | |
224 | 11.6M | memset(repeat_count, 0x00, MAX_PSC_FUNCTION_NESTING * sizeof(int)); |
225 | 11.6M | memset(repeat_proc_size, 0x00, MAX_PSC_FUNCTION_NESTING * sizeof(int)); |
226 | | |
227 | 11.6M | vstack[-1].type = CVT_NONE; /* for type dispatch in empty stack case */ |
228 | 11.6M | vstack[0].type = CVT_NONE; /* catch underflow */ |
229 | 52.0M | for (i = 0; i < pfn->params.m; ++i) |
230 | 40.4M | store_float(&vstack[i + 1], in[i]); |
231 | | |
232 | 212M | for (; ; ) { |
233 | 212M | int code, n; |
234 | | |
235 | 212M | switch (op_defn_table[*p++].opcode[(vsp[-1].type << 2) + vsp->type]) { |
236 | | |
237 | | /* Miscellaneous */ |
238 | | |
239 | 2.60M | case PtCr_no_op: |
240 | 2.60M | continue; |
241 | 26 | case PtCr_typecheck: |
242 | 26 | return_error(gs_error_typecheck); |
243 | | |
244 | | /* Coerce and re-dispatch */ |
245 | | |
246 | 13.7M | case PtCr_int_to_float: |
247 | 13.7M | store_float(vsp, (double)vsp->value.i); |
248 | 13.7M | --p; continue; |
249 | 127k | case PtCr_int2_to_float: |
250 | 127k | store_float(vsp, (double)vsp->value.i); |
251 | | /* fall through */ |
252 | 3.99M | case PtCr_2nd_int_to_float: |
253 | 3.99M | store_float(vsp - 1, (double)vsp[-1].value.i); |
254 | 3.99M | --p; continue; |
255 | | |
256 | | /* Arithmetic operators */ |
257 | | |
258 | 3.57M | case PtCr_abs: |
259 | 3.57M | vsp->value.f = fabs(vsp->value.f); |
260 | 3.57M | 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 | 127k | } |
270 | 2.21M | case PtCr_add: |
271 | 2.21M | vsp[-1].value.f += vsp->value.f; |
272 | 2.21M | --vsp; continue; |
273 | 0 | case PtCr_and: |
274 | 0 | vsp[-1].value.i &= vsp->value.i; |
275 | 0 | --vsp; continue; |
276 | 2.58M | case PtCr_atan: { |
277 | 2.58M | double result; |
278 | | |
279 | 2.58M | code = gs_atan2_degrees(vsp[-1].value.f, vsp->value.f, |
280 | 2.58M | &result); |
281 | 2.58M | if (code < 0) |
282 | 0 | return code; |
283 | 2.58M | vsp[-1].value.f = result; |
284 | 2.58M | --vsp; continue; |
285 | 2.58M | } |
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 | 2.58M | case PtCr_cos: |
300 | 2.58M | vsp->value.f = gs_cos_degrees(vsp->value.f); |
301 | 2.58M | 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 | 2.58M | } |
313 | 0 | case PtCr_cvr: |
314 | 0 | continue; /* prepare handled it */ |
315 | 3.26M | case PtCr_div: |
316 | 3.26M | if (vsp->value.f == 0) |
317 | 0 | return_error(gs_error_undefinedresult); |
318 | 3.26M | vsp[-1].value.f /= vsp->value.f; |
319 | 3.26M | --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 | 2.88M | case PtCr_mul_int: { |
347 | | /* We don't bother to optimize this. */ |
348 | 2.88M | double prod = (double)vsp[-1].value.i * vsp->value.i; |
349 | | |
350 | 2.88M | if (prod < min_int || prod > max_int) |
351 | 0 | store_float(vsp - 1, prod); |
352 | 2.88M | else |
353 | 2.88M | vsp[-1].value.i = (int)prod; |
354 | 2.88M | --vsp; continue; |
355 | 0 | } |
356 | 6.33M | case PtCr_mul: |
357 | 6.33M | vsp[-1].value.f *= vsp->value.f; |
358 | 6.33M | --vsp; continue; |
359 | 127k | case PtCr_abs_int: |
360 | 127k | if (vsp->value.i >= 0) |
361 | 127k | 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 | 3.26M | case PtCr_sin: |
385 | 3.26M | vsp->value.f = gs_sin_degrees(vsp->value.f); |
386 | 3.26M | continue; |
387 | 3.26M | case PtCr_sqrt: |
388 | 3.26M | vsp->value.f = sqrt(vsp->value.f); |
389 | 3.26M | continue; |
390 | 642k | case PtCr_sub_int: { |
391 | 642k | int int1 = vsp[-1].value.i, int2 = vsp->value.i; |
392 | | |
393 | 642k | if ((int1 ^ int2) < 0 && ((int1 - int2) ^ int1) >= 0) |
394 | 0 | store_float(vsp - 1, (double)int1 - int2); |
395 | 642k | else |
396 | 642k | vsp[-1].value.i = int1 - int2; |
397 | 642k | --vsp; continue; |
398 | 127k | } |
399 | 13.4M | case PtCr_sub: |
400 | 13.4M | vsp[-1].value.f -= vsp->value.f; |
401 | 13.4M | --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 | 3.41M | 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 | 18 | case PtCr_ge_int: |
419 | 18 | DO_REL(>=, i); |
420 | 18 | goto rel; |
421 | 46 | case PtCr_ge: |
422 | 46 | DO_REL(>=, f); |
423 | 46 | goto rel; |
424 | 312 | case PtCr_gt_int: |
425 | 312 | DO_REL(>, i); |
426 | 312 | goto rel; |
427 | 104 | case PtCr_gt: |
428 | 104 | DO_REL(>, f); |
429 | 104 | goto rel; |
430 | 0 | case PtCr_le_int: |
431 | 0 | DO_REL(<=, i); |
432 | 0 | goto rel; |
433 | 154k | case PtCr_le: |
434 | 154k | DO_REL(<=, f); |
435 | 154k | goto rel; |
436 | 0 | case PtCr_lt_int: |
437 | 0 | DO_REL(<, i); |
438 | 0 | goto rel; |
439 | 3.26M | case PtCr_lt: |
440 | 3.26M | DO_REL(<, f); |
441 | 3.26M | 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 | 3.41M | rel: |
451 | 3.41M | vsp[-1].type = CVT_BOOL; |
452 | 3.41M | --vsp; continue; |
453 | | |
454 | 0 | #undef DO_REL |
455 | | |
456 | | /* Stack operators */ |
457 | | |
458 | 154k | case PtCr_copy: |
459 | 154k | i = vsp->value.i; |
460 | 154k | n = vsp - vstack; |
461 | 154k | if (i < 0 || i >= n) |
462 | 0 | return_error(gs_error_rangecheck); |
463 | 154k | if (i > MAX_VSTACK - (n - 1)) |
464 | 0 | return_error(gs_error_limitcheck); |
465 | 154k | memcpy(vsp, vsp - i, i * sizeof(*vsp)); |
466 | 154k | vsp += i - 1; |
467 | 154k | continue; |
468 | 13.5M | case PtCr_dup: |
469 | 13.5M | vsp[1] = *vsp; |
470 | 13.5M | goto push; |
471 | 18.8M | case PtCr_exch: |
472 | 18.8M | vstack[MAX_VSTACK] = *vsp; |
473 | 18.8M | *vsp = vsp[-1]; |
474 | 18.8M | vsp[-1] = vstack[MAX_VSTACK]; |
475 | 18.8M | continue; |
476 | 2.63M | case PtCr_index: |
477 | 2.63M | i = vsp->value.i; |
478 | 2.63M | if (i < 0 || i >= vsp - vstack - 1) |
479 | 0 | return_error(gs_error_rangecheck); |
480 | 2.63M | *vsp = vsp[-i - 1]; |
481 | 2.63M | continue; |
482 | 14.8M | case PtCr_pop: |
483 | 14.8M | --vsp; |
484 | 14.8M | continue; |
485 | 15.0M | case PtCr_roll: |
486 | 15.0M | n = vsp[-1].value.i; |
487 | 15.0M | i = vsp->value.i; |
488 | 15.0M | if (n < 0 || n > vsp - vstack - 2) |
489 | 0 | return_error(gs_error_rangecheck); |
490 | | /* We don't bother to do this efficiently. */ |
491 | 42.2M | for (; i > 0; i--) { |
492 | 27.1M | memmove(vsp - n, vsp - (n + 1), n * sizeof(*vsp)); |
493 | 27.1M | vsp[-(n + 1)] = vsp[-1]; |
494 | 27.1M | } |
495 | 17.9M | for (; i < 0; i++) { |
496 | 2.88M | vsp[-1] = vsp[-(n + 1)]; |
497 | 2.88M | memmove(vsp - (n + 1), vsp - n, n * sizeof(*vsp)); |
498 | 2.88M | } |
499 | 15.0M | vsp -= 2; |
500 | 15.0M | continue; |
501 | | |
502 | | /* Constants */ |
503 | | |
504 | 46.2M | case PtCr_byte: |
505 | 46.2M | vsp[1].value.i = *p++, vsp[1].type = CVT_INT; |
506 | 46.2M | goto push; |
507 | 8.73M | case PtCr_int /* native */: |
508 | 8.73M | memcpy(&vsp[1].value.i, p, sizeof(int)); |
509 | 8.73M | vsp[1].type = CVT_INT; |
510 | 8.73M | p += sizeof(int); |
511 | 8.73M | goto push; |
512 | 9.41M | case PtCr_float /* native */: |
513 | 9.41M | memcpy(&vsp[1].value.f, p, sizeof(float)); |
514 | 9.41M | vsp[1].type = CVT_FLOAT; |
515 | 9.41M | p += sizeof(float); |
516 | 9.41M | 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 | 77.9M | push: |
523 | 77.9M | if (vsp == &vstack[MAX_VSTACK]) |
524 | 1 | return_error(gs_error_limitcheck); |
525 | 77.9M | ++vsp; |
526 | 77.9M | continue; |
527 | | |
528 | | /* Special */ |
529 | | |
530 | 3.41M | case PtCr_if: |
531 | 3.41M | if ((vsp--)->value.i) { /* value is true, execute body */ |
532 | 2.95M | p += 2; |
533 | 2.95M | continue; |
534 | 2.95M | } |
535 | | /* falls through */ |
536 | 538k | case PtCr_else: |
537 | 538k | p += 2 + (p[0] << 8) + p[1]; /* skip the past body */ |
538 | 538k | continue; |
539 | 11.6M | case PtCr_return: |
540 | 11.6M | 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 | 212M | } |
558 | 212M | } |
559 | 11.6M | fin: |
560 | 11.6M | { /* Following Acrobat, take the desired number of parameters */ |
561 | | /* from the top of stack and ignore the rest. Bug 702950. */ |
562 | 11.6M | int extra_ops = vsp - vstack - pfn->params.n; |
563 | 11.6M | if (extra_ops < 0) |
564 | 24 | return_error(gs_error_rangecheck); |
565 | 46.7M | for (i = 0; i < pfn->params.n; ++i) { |
566 | 35.1M | switch (vstack[i + 1 + extra_ops].type) { |
567 | 654k | case CVT_INT: |
568 | 654k | out[i] = (float)vstack[i + 1 + extra_ops].value.i; |
569 | 654k | break; |
570 | 34.4M | case CVT_FLOAT: |
571 | 34.4M | out[i] = vstack[i + 1 + extra_ops].value.f; |
572 | 34.4M | break; |
573 | 0 | default: |
574 | 0 | return_error(gs_error_typecheck); |
575 | 35.1M | } |
576 | 35.1M | } |
577 | 11.6M | } |
578 | 11.6M | return 0; |
579 | 11.6M | } |
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 | 1.43k | { |
600 | 1.43k | const byte *p; |
601 | | |
602 | 1.43k | spputc(s, '{'); |
603 | 9.49k | for (p = ops; p < ops + size; ) |
604 | 8.05k | switch (*p++) { |
605 | 2.30k | case PtCr_byte: |
606 | 2.30k | pprintd1(s, "%d ", *p++); |
607 | 2.30k | break; |
608 | 443 | case PtCr_int: { |
609 | 443 | int i; |
610 | | |
611 | 443 | memcpy(&i, p, sizeof(int)); |
612 | 443 | pprintd1(s, "%d ", i); |
613 | 443 | p += sizeof(int); |
614 | 443 | break; |
615 | 0 | } |
616 | 2.33k | case PtCr_float: { |
617 | 2.33k | float f; |
618 | | |
619 | 2.33k | memcpy(&f, p, sizeof(float)); |
620 | 2.33k | pprintg1(s, "%g ", f); |
621 | 2.33k | p += sizeof(float); |
622 | 2.33k | 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 | 176 | case PtCr_if: { |
631 | 176 | int skip = (p[0] << 8) + p[1]; |
632 | 176 | int code; |
633 | | |
634 | 176 | code = calc_put_ops(s, p += 2, skip); |
635 | 176 | p += skip; |
636 | 176 | if (code < 0) |
637 | 0 | return code; |
638 | 176 | 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 | 176 | stream_puts(s, " if "); |
647 | 176 | break; |
648 | 176 | } |
649 | 176 | 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 | 2.79k | default: { /* must be < PtCr_NUM_OPS */ |
659 | 2.79k | static const char *const op_names[] = { |
660 | | /* Keep this consistent with opcodes in gsfunc4.h! */ |
661 | 2.79k | "abs", "add", "and", "atan", "bitshift", |
662 | 2.79k | "ceiling", "cos", "cvi", "cvr", "div", "exp", |
663 | 2.79k | "floor", "idiv", "ln", "log", "mod", "mul", |
664 | 2.79k | "neg", "not", "or", "round", "sin", "sqrt", "sub", |
665 | 2.79k | "truncate", "xor", |
666 | 2.79k | "eq", "ge", "gt", "le", "lt", "ne", |
667 | 2.79k | "copy", "dup", "exch", "index", "pop", "roll" |
668 | 2.79k | }; |
669 | | |
670 | 2.79k | pprints1(s, "%s ", op_names[p[-1]]); |
671 | 2.79k | } |
672 | 8.05k | } |
673 | 1.43k | spputc(s, '}'); |
674 | 1.43k | return 0; |
675 | 1.43k | } |
676 | | static int |
677 | | calc_put(stream *s, const gs_function_PtCr_t *pfn) |
678 | 1.26k | { |
679 | 1.26k | calc_put_ops(s, pfn->params.ops.data, pfn->params.ops.size - 1); |
680 | 1.26k | return 0; |
681 | 1.26k | } |
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 | 642 | { |
688 | 642 | const gs_function_PtCr_t *const pfn = |
689 | 642 | (const gs_function_PtCr_t *) |
690 | 642 | ((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 | 642 | stream_SFD_state st; |
700 | 642 | stream ds, bs; |
701 | 642 | byte dbuf[200]; /* arbitrary */ |
702 | 642 | const stream_template *const templat = &s_SFD_template; |
703 | | |
704 | | /* Set up the stream that writes into the buffer. */ |
705 | 642 | s_init(&bs, NULL); |
706 | 642 | swrite_string(&bs, buf, length); |
707 | | /* Set up the SubFileDecode stream. */ |
708 | 642 | s_init(&ds, NULL); |
709 | 642 | s_init_state((stream_state *)&st, templat, NULL); |
710 | 642 | templat->set_defaults((stream_state *)&st); |
711 | 642 | st.skip_count = start; |
712 | 642 | s_init_filter(&ds, (stream_state *)&st, dbuf, sizeof(dbuf), &bs); |
713 | 642 | calc_put(&ds, pfn); |
714 | 642 | sclose(&ds); |
715 | 642 | if (ptr) |
716 | 642 | *ptr = buf; |
717 | 642 | return 0; |
718 | 642 | } |
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 | 621 | { |
724 | 621 | const gs_function_PtCr_t *const pfn = |
725 | 621 | (const gs_function_PtCr_t *)pfn_common; |
726 | | |
727 | 621 | gs_function_get_info_default(pfn_common, pfi); |
728 | 621 | pfi->DataSource = &pfn->data_source; |
729 | 621 | { |
730 | 621 | stream s; |
731 | | |
732 | 621 | s_init(&s, NULL); |
733 | 621 | swrite_position_only(&s); |
734 | 621 | calc_put(&s, pfn); |
735 | 621 | pfi->data_size = stell(&s); |
736 | 621 | } |
737 | 621 | } |
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 | 57.5k | { |
805 | 57.5k | gs_free_const_string(mem, params->ops.data, params->ops.size, "ops"); |
806 | 57.5k | params->ops.data = NULL; |
807 | 57.5k | params->ops.size = 0; |
808 | 57.5k | fn_common_free_params((gs_function_params_t *) params, mem); |
809 | 57.5k | } |
810 | | |
811 | | /* Serialize. */ |
812 | | static int |
813 | | gs_function_PtCr_serialize(const gs_function_t * pfn, stream *s) |
814 | 20.0k | { |
815 | 20.0k | uint n; |
816 | 20.0k | const gs_function_PtCr_params_t * p = (const gs_function_PtCr_params_t *)&pfn->params; |
817 | 20.0k | int code = fn_common_serialize(pfn, s); |
818 | | |
819 | 20.0k | if (code < 0) |
820 | 0 | return code; |
821 | 20.0k | code = sputs(s, (const byte *)&p->ops.size, sizeof(p->ops.size), &n); |
822 | 20.0k | if (code < 0) |
823 | 0 | return code; |
824 | 20.0k | return sputs(s, p->ops.data, p->ops.size, &n); |
825 | 20.0k | } |
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 | 60.7k | { |
832 | 60.7k | static const gs_function_head_t function_PtCr_head = { |
833 | 60.7k | function_type_PostScript_Calculator, |
834 | 60.7k | { |
835 | 60.7k | (fn_evaluate_proc_t) fn_PtCr_evaluate, |
836 | 60.7k | (fn_is_monotonic_proc_t) fn_PtCr_is_monotonic, |
837 | 60.7k | (fn_get_info_proc_t) fn_PtCr_get_info, |
838 | 60.7k | fn_common_get_params, |
839 | 60.7k | (fn_make_scaled_proc_t) fn_PtCr_make_scaled, |
840 | 60.7k | (fn_free_params_proc_t) gs_function_PtCr_free_params, |
841 | 60.7k | fn_common_free, |
842 | 60.7k | (fn_serialize_proc_t) gs_function_PtCr_serialize, |
843 | 60.7k | } |
844 | 60.7k | }; |
845 | 60.7k | int code; |
846 | | |
847 | 60.7k | *ppfn = 0; /* in case of error */ |
848 | 60.7k | code = fn_check_mnDR((const gs_function_params_t *)params, |
849 | 60.7k | params->m, params->n); |
850 | 60.7k | if (code < 0) |
851 | 15 | return code; |
852 | 60.7k | 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 | 60.7k | { |
858 | 60.7k | const byte *p = params->ops.data; |
859 | | |
860 | 2.64M | for (; *p != PtCr_return; ++p) |
861 | 2.58M | switch ((gs_PtCr_opcode_t)*p) { |
862 | 801k | case PtCr_byte: |
863 | 801k | ++p; break; |
864 | 141k | case PtCr_int: |
865 | 141k | p += sizeof(int); break; |
866 | 181k | case PtCr_float: |
867 | 181k | p += sizeof(float); break; |
868 | 0 | case PtCr_repeat: |
869 | 19.8k | case PtCr_if: |
870 | 39.1k | case PtCr_else: |
871 | 39.1k | p += 2; |
872 | 39.1k | case PtCr_repeat_end: |
873 | 39.1k | case PtCr_true: |
874 | 39.1k | case PtCr_false: |
875 | 39.1k | break; |
876 | 1.41M | default: |
877 | 1.41M | if (*p >= PtCr_NUM_OPS) |
878 | 0 | return_error(gs_error_rangecheck); |
879 | 2.58M | } |
880 | 60.7k | if (p != params->ops.data + params->ops.size - 1) |
881 | 0 | return_error(gs_error_rangecheck); |
882 | 60.7k | } |
883 | 60.7k | { |
884 | 60.7k | gs_function_PtCr_t *pfn = |
885 | 60.7k | gs_alloc_struct(mem, gs_function_PtCr_t, &st_function_PtCr, |
886 | 60.7k | "gs_function_PtCr_init"); |
887 | | |
888 | 60.7k | if (pfn == 0) |
889 | 0 | return_error(gs_error_VMerror); |
890 | 60.7k | 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 | 60.7k | data_source_init_string2(&pfn->data_source, NULL, 0); |
897 | 60.7k | pfn->data_source.access = calc_access; |
898 | 60.7k | pfn->head = function_PtCr_head; |
899 | 60.7k | *ppfn = (gs_function_t *) pfn; |
900 | 60.7k | } |
901 | 0 | return 0; |
902 | 60.7k | } |