/src/ghostpdl/base/gsfunc4.c
Line | Count | Source |
1 | | /* Copyright (C) 2001-2026 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 | 87.5M | #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 | 38.0M | { |
67 | 38.0M | vsp->value.f = f; |
68 | 38.0M | vsp->type = CVT_FLOAT; |
69 | 38.0M | } |
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 | 6.37M | { |
109 | 6.37M | const gs_function_PtCr_t *pfn = (const gs_function_PtCr_t *)pfn_common; |
110 | 6.37M | calc_value_t vstack_buf[2 + MAX_VSTACK + 1]; |
111 | 6.37M | calc_value_t *vstack = &vstack_buf[1]; |
112 | 6.37M | calc_value_t *vsp = vstack + pfn->params.m; |
113 | 6.37M | const byte *p = pfn->params.ops.data; |
114 | 6.37M | int repeat_count[MAX_PSC_FUNCTION_NESTING]; |
115 | 6.37M | int repeat_proc_size[MAX_PSC_FUNCTION_NESTING]; |
116 | 6.37M | int repeat_nesting_level = -1; |
117 | 6.37M | 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 | 6.37M | static const struct op_defn_s { |
125 | 6.37M | byte opcode[16]; /* 4 * type[-1] + type[0] */ |
126 | 6.37M | } op_defn_table[] = { |
127 | | /* Keep this consistent with opcodes in gsfunc4.h! */ |
128 | | |
129 | 465M | #define O4(op) op,op,op,op |
130 | 1.02G | #define E PtCr_typecheck |
131 | 261M | #define E4 O4(E) |
132 | 6.37M | #define N PtCr_no_op |
133 | | /* 0-operand operators */ |
134 | 6.37M | #define OP_NONE(op)\ |
135 | 51.0M | {{O4(op), O4(op), O4(op), O4(op)}} |
136 | | /* 1-operand operators */ |
137 | 6.37M | #define OP1(b, i, f)\ |
138 | 127M | {{E,b,i,f, E,b,i,f, E,b,i,f, E,b,i,f}} |
139 | 6.37M | #define OP_NUM1(i, f)\ |
140 | 51.0M | OP1(E, i, f) |
141 | 6.37M | #define OP_MATH1(f)\ |
142 | 31.8M | OP1(E, PtCr_int_to_float, f) |
143 | 6.37M | #define OP_ANY1(op)\ |
144 | 12.7M | OP1(op, op, op) |
145 | | /* 2-operand operators */ |
146 | 6.37M | #define OP_NUM2(i, f)\ |
147 | 44.6M | {{E4, E4, E,E,i,PtCr_2nd_int_to_float, E,E,PtCr_int_to_float,f}} |
148 | 6.37M | #define OP_INT_BOOL2(i)\ |
149 | 19.1M | {{E4, E,i,i,E, E,i,i,E, E4}} |
150 | 6.37M | #define OP_MATH2(f)\ |
151 | 19.1M | {{E4, E4, E,E,PtCr_int2_to_float,PtCr_2nd_int_to_float,\ |
152 | 19.1M | E,E,PtCr_int_to_float,f}} |
153 | 6.37M | #define OP_INT2(i)\ |
154 | 25.5M | {{E4, E4, E,E,i,E, E4}} |
155 | 6.37M | #define OP_REL2(i, f)\ |
156 | 12.7M | {{E4, E,i,E,E, E,E,i,PtCr_2nd_int_to_float, E,E,PtCr_int_to_float,f}} |
157 | 6.37M | #define OP_ANY2(op)\ |
158 | 6.37M | {{E4, E,op,op,op, E,op,op,op, E,op,op,op}} |
159 | | |
160 | | /* Arithmetic operators */ |
161 | | |
162 | 6.37M | OP_NUM1(PtCr_abs_int, PtCr_abs), /* abs */ |
163 | 6.37M | OP_NUM2(PtCr_add_int, PtCr_add), /* add */ |
164 | 6.37M | OP_INT_BOOL2(PtCr_and), /* and */ |
165 | 6.37M | OP_MATH2(PtCr_atan), /* atan */ |
166 | 6.37M | OP_INT2(PtCr_bitshift), /* bitshift */ |
167 | 6.37M | OP_NUM1(N, PtCr_ceiling), /* ceiling */ |
168 | 6.37M | OP_MATH1(PtCr_cos), /* cos */ |
169 | 6.37M | OP_NUM1(N, PtCr_cvi), /* cvi */ |
170 | 6.37M | OP_NUM1(PtCr_int_to_float, N), /* cvr */ |
171 | 6.37M | OP_MATH2(PtCr_div), /* div */ |
172 | 6.37M | OP_MATH2(PtCr_exp), /* exp */ |
173 | 6.37M | OP_NUM1(N, PtCr_floor), /* floor */ |
174 | 6.37M | OP_INT2(PtCr_idiv), /* idiv */ |
175 | 6.37M | OP_MATH1(PtCr_ln), /* ln */ |
176 | 6.37M | OP_MATH1(PtCr_log), /* log */ |
177 | 6.37M | OP_INT2(PtCr_mod), /* mod */ |
178 | 6.37M | OP_NUM2(PtCr_mul_int, PtCr_mul), /* mul */ |
179 | 6.37M | OP_NUM1(PtCr_neg_int, PtCr_neg), /* neg */ |
180 | 6.37M | OP1(PtCr_not, PtCr_not, E), /* not */ |
181 | 6.37M | OP_INT_BOOL2(PtCr_or), /* or */ |
182 | 6.37M | OP_NUM1(N, PtCr_round), /* round */ |
183 | 6.37M | OP_MATH1(PtCr_sin), /* sin */ |
184 | 6.37M | OP_MATH1(PtCr_sqrt), /* sqrt */ |
185 | 6.37M | OP_NUM2(PtCr_sub_int, PtCr_sub), /* sub */ |
186 | 6.37M | OP_NUM1(N, PtCr_truncate), /* truncate */ |
187 | 6.37M | OP_INT_BOOL2(PtCr_xor), /* xor */ |
188 | | |
189 | | /* Comparison operators */ |
190 | | |
191 | 6.37M | OP_REL2(PtCr_eq_int, PtCr_eq), /* eq */ |
192 | 6.37M | OP_NUM2(PtCr_ge_int, PtCr_ge), /* ge */ |
193 | 6.37M | OP_NUM2(PtCr_gt_int, PtCr_gt), /* gt */ |
194 | 6.37M | OP_NUM2(PtCr_le_int, PtCr_le), /* le */ |
195 | 6.37M | OP_NUM2(PtCr_lt_int, PtCr_lt), /* lt */ |
196 | 6.37M | OP_REL2(PtCr_ne_int, PtCr_ne), /* ne */ |
197 | | |
198 | | /* Stack operators */ |
199 | | |
200 | 6.37M | OP1(E, PtCr_copy, E), /* copy */ |
201 | 6.37M | OP_ANY1(PtCr_dup), /* dup */ |
202 | 6.37M | OP_ANY2(PtCr_exch), /* exch */ |
203 | 6.37M | OP1(E, PtCr_index, E), /* index */ |
204 | 6.37M | OP_ANY1(PtCr_pop), /* pop */ |
205 | 6.37M | OP_INT2(PtCr_roll), /* roll */ |
206 | | |
207 | | /* Constants */ |
208 | | |
209 | 6.37M | OP_NONE(PtCr_byte), /* byte */ |
210 | 6.37M | OP_NONE(PtCr_int), /* int */ |
211 | 6.37M | OP_NONE(PtCr_float), /* float */ |
212 | 6.37M | OP_NONE(PtCr_true), /* true */ |
213 | 6.37M | OP_NONE(PtCr_false), /* false */ |
214 | | |
215 | | /* Special */ |
216 | | |
217 | 6.37M | OP1(PtCr_if, E, E), /* if */ |
218 | 6.37M | OP_NONE(PtCr_else), /* else */ |
219 | 6.37M | OP_NONE(PtCr_return), /* return */ |
220 | 6.37M | OP1(E, PtCr_repeat, E), /* repeat */ |
221 | 6.37M | OP_NONE(PtCr_repeat_end) /* repeat_end */ |
222 | 6.37M | }; |
223 | | |
224 | 6.37M | memset(repeat_count, 0x00, MAX_PSC_FUNCTION_NESTING * sizeof(int)); |
225 | 6.37M | memset(repeat_proc_size, 0x00, MAX_PSC_FUNCTION_NESTING * sizeof(int)); |
226 | | |
227 | 6.37M | vstack[-1].type = CVT_NONE; /* for type dispatch in empty stack case */ |
228 | 6.37M | vstack[0].type = CVT_NONE; /* catch underflow */ |
229 | 26.5M | for (i = 0; i < pfn->params.m; ++i) |
230 | 20.1M | store_float(&vstack[i + 1], in[i]); |
231 | | |
232 | 162M | for (; ; ) { |
233 | 162M | int code, n; |
234 | | |
235 | 162M | switch (op_defn_table[*p++].opcode[(vsp[-1].type << 2) + vsp->type]) { |
236 | | |
237 | | /* Miscellaneous */ |
238 | | |
239 | 2.10M | case PtCr_no_op: |
240 | 2.10M | continue; |
241 | 35 | case PtCr_typecheck: |
242 | 35 | return_error(gs_error_typecheck); |
243 | | |
244 | | /* Coerce and re-dispatch */ |
245 | | |
246 | 14.0M | case PtCr_int_to_float: |
247 | 14.0M | store_float(vsp, (double)vsp->value.i); |
248 | 14.0M | --p; continue; |
249 | 159k | case PtCr_int2_to_float: |
250 | 159k | store_float(vsp, (double)vsp->value.i); |
251 | | /* fall through */ |
252 | 3.69M | case PtCr_2nd_int_to_float: |
253 | 3.69M | store_float(vsp - 1, (double)vsp[-1].value.i); |
254 | 3.69M | --p; continue; |
255 | | |
256 | | /* Arithmetic operators */ |
257 | | |
258 | 3.89M | case PtCr_abs: |
259 | 3.89M | vsp->value.f = fabs(vsp->value.f); |
260 | 3.89M | continue; |
261 | 0 | case PtCr_add_int: { |
262 | 0 | int int1 = vsp[-1].value.i, int2 = vsp->value.i; |
263 | | |
264 | | /* Test the signs first, if they are different then integer addition can't overflow */ |
265 | 0 | if ((int1 ^ int2) < 0) { |
266 | 0 | vsp[-1].value.i = int1 - int2; |
267 | 0 | } else { |
268 | 0 | unsigned int u1, u2; |
269 | |
|
270 | 0 | if (int1 < 0) { |
271 | | /* minimum signed int converted to unsigned, doubled, can overflow */ |
272 | 0 | u1 = (unsigned int)(~int1) + 1; |
273 | 0 | u2 = u1 + (unsigned int)(~int2) + 1; |
274 | |
|
275 | 0 | if (u2 < u1 || u2 > (unsigned int)max_int + 1) |
276 | 0 | store_float(vsp - 1, (double)int1 - int2); |
277 | 0 | else |
278 | 0 | vsp[-1].value.i = int1 - int2; |
279 | 0 | } else { |
280 | | /* maximum signed int + maximum signed int fits into an unsigned int, so no overflow */ |
281 | 0 | u1 = int1 + int2; |
282 | |
|
283 | 0 | if (u1 > (unsigned int)max_int) |
284 | 0 | store_float(vsp - 1, (double)int1 - int2); |
285 | 0 | else |
286 | 0 | vsp[-1].value.i = int1 - int2; |
287 | 0 | } |
288 | 0 | } |
289 | 0 | --vsp; continue; |
290 | 159k | } |
291 | 1.19M | case PtCr_add: |
292 | 1.19M | vsp[-1].value.f += vsp->value.f; |
293 | 1.19M | --vsp; continue; |
294 | 0 | case PtCr_and: |
295 | 0 | vsp[-1].value.i &= vsp->value.i; |
296 | 0 | --vsp; continue; |
297 | 2.58M | case PtCr_atan: { |
298 | 2.58M | double result; |
299 | | |
300 | 2.58M | code = gs_atan2_degrees(vsp[-1].value.f, vsp->value.f, |
301 | 2.58M | &result); |
302 | 2.58M | if (code < 0) |
303 | 0 | return code; |
304 | 2.58M | vsp[-1].value.f = result; |
305 | 2.58M | --vsp; continue; |
306 | 2.58M | } |
307 | 0 | case PtCr_bitshift: |
308 | 0 | #define MAX_SHIFT (ARCH_SIZEOF_INT * 8 - 1) |
309 | 0 | if (vsp->value.i < -MAX_SHIFT || vsp->value.i > MAX_SHIFT) |
310 | 0 | vsp[-1].value.i = 0; |
311 | 0 | #undef MAX_SHIFT |
312 | 0 | else if ((n = vsp->value.i) < 0) |
313 | 0 | vsp[-1].value.i = ((uint)(vsp[-1].value.i)) >> -n; |
314 | 0 | else |
315 | 0 | vsp[-1].value.i <<= n; |
316 | 0 | --vsp; continue; |
317 | 0 | case PtCr_ceiling: |
318 | 0 | vsp->value.f = ceil(vsp->value.f); |
319 | 0 | continue; |
320 | 2.58M | case PtCr_cos: |
321 | 2.58M | vsp->value.f = gs_cos_degrees(vsp->value.f); |
322 | 2.58M | continue; |
323 | 0 | case PtCr_cvi: |
324 | 0 | { |
325 | | /* Strictly speaking assigning one element of union |
326 | | * to another, overlapping element of a different size is |
327 | | * undefined behavior, hence assign to an intermediate variable |
328 | | */ |
329 | 0 | int int1 = (int)(vsp->value.f); |
330 | 0 | vsp->value.i = int1; |
331 | 0 | vsp->type = CVT_INT; |
332 | 0 | continue; |
333 | 2.58M | } |
334 | 0 | case PtCr_cvr: |
335 | 0 | continue; /* prepare handled it */ |
336 | 3.29M | case PtCr_div: |
337 | 3.29M | if (vsp->value.f == 0) |
338 | 0 | return_error(gs_error_undefinedresult); |
339 | 3.29M | vsp[-1].value.f /= vsp->value.f; |
340 | 3.29M | --vsp; continue; |
341 | 0 | case PtCr_exp: |
342 | 0 | vsp[-1].value.f = pow(vsp[-1].value.f, vsp->value.f); |
343 | 0 | --vsp; continue; |
344 | 0 | case PtCr_floor: |
345 | 0 | vsp->value.f = floor(vsp->value.f); |
346 | 0 | continue; |
347 | 0 | case PtCr_idiv: |
348 | 0 | if (vsp->value.i == 0) |
349 | 0 | return_error(gs_error_undefinedresult); |
350 | 0 | if (vsp[-1].value.i == min_int && |
351 | 0 | vsp->value.i == -1) /* anomalous boundary case, fail */ |
352 | 0 | return_error(gs_error_rangecheck); |
353 | 0 | else |
354 | 0 | vsp[-1].value.i /= vsp->value.i; |
355 | 0 | --vsp; continue; |
356 | 0 | case PtCr_ln: |
357 | 0 | vsp->value.f = log(vsp->value.f); |
358 | 0 | continue; |
359 | 0 | case PtCr_log: |
360 | 0 | vsp->value.f = log10(vsp->value.f); |
361 | 0 | continue; |
362 | 0 | case PtCr_mod: |
363 | 0 | if (vsp->value.i == 0) |
364 | 0 | return_error(gs_error_undefinedresult); |
365 | 0 | if (vsp[-1].value.i == min_int && |
366 | 0 | vsp->value.i == -1) /* anomalous boundary case, fail */ |
367 | 0 | return_error(gs_error_rangecheck); |
368 | 0 | vsp[-1].value.i %= vsp->value.i; |
369 | 0 | --vsp; continue; |
370 | 2.89M | case PtCr_mul_int: { |
371 | | /* We don't bother to optimize this. */ |
372 | 2.89M | double prod = (double)vsp[-1].value.i * vsp->value.i; |
373 | | |
374 | 2.89M | if (prod < min_int || prod > max_int) |
375 | 0 | store_float(vsp - 1, prod); |
376 | 2.89M | else |
377 | 2.89M | vsp[-1].value.i = (int)prod; |
378 | 2.89M | --vsp; continue; |
379 | 0 | } |
380 | 4.36M | case PtCr_mul: |
381 | 4.36M | vsp[-1].value.f *= vsp->value.f; |
382 | 4.36M | --vsp; continue; |
383 | 159k | case PtCr_abs_int: |
384 | 159k | if (vsp->value.i >= 0) |
385 | 159k | continue; |
386 | | /* fallthrough */ |
387 | 0 | case PtCr_neg_int: |
388 | 0 | if (vsp->value.i == min_int) |
389 | 0 | store_float(vsp, (double)vsp->value.i); /* =self negated */ |
390 | 0 | else |
391 | 0 | vsp->value.i = -vsp->value.i; |
392 | 0 | continue; |
393 | 0 | case PtCr_neg: |
394 | 0 | vsp->value.f = -vsp->value.f; |
395 | 0 | continue; |
396 | 0 | case PtCr_not_bool: |
397 | 0 | vsp->value.i = !vsp->value.i; |
398 | 0 | continue; |
399 | 0 | case PtCr_not: |
400 | 0 | vsp->value.i = ~vsp->value.i; |
401 | 0 | continue; |
402 | 0 | case PtCr_or: |
403 | 0 | vsp[-1].value.i |= vsp->value.i; |
404 | 0 | --vsp; continue; |
405 | 0 | case PtCr_round: |
406 | 0 | vsp->value.f = floor(vsp->value.f + 0.5); |
407 | 0 | continue; |
408 | 3.29M | case PtCr_sin: |
409 | 3.29M | vsp->value.f = gs_sin_degrees(vsp->value.f); |
410 | 3.29M | continue; |
411 | 3.29M | case PtCr_sqrt: |
412 | 3.29M | if (vsp->value.f < 0.0) |
413 | 0 | return_error(gs_error_rangecheck); |
414 | 3.29M | vsp->value.f = sqrt(vsp->value.f); |
415 | 3.29M | continue; |
416 | 0 | case PtCr_sub_int: { |
417 | 0 | int int1 = vsp[-1].value.i, int2 = vsp->value.i; |
418 | | |
419 | | /* Test the signs first, if they are the same then integer subtraction can't overflow */ |
420 | 0 | if ((int1 ^ int2) >= 0) { |
421 | 0 | vsp[-1].value.i = int1 - int2; |
422 | 0 | } else { |
423 | 0 | unsigned int u1, u2; |
424 | |
|
425 | 0 | if (int1 < 0) { |
426 | | /* -ve minus +ve, convert -ve to +ve and add as unsigned, defined behaviour if overflow (wraps round) */ |
427 | 0 | u1 = (unsigned int)(~int1) + 1; |
428 | 0 | u2 = u1 + int2; |
429 | | /* If adding 2 positive values produced a smaller value, then the addition overflowed. |
430 | | * If the result is larger than the max signed int (+1 for -ve) then subtraction will overflow |
431 | | */ |
432 | 0 | if (u2 < u1 || u2 > ((unsigned int)max_int + 1)) |
433 | 0 | store_float(vsp - 1, (double)int1 - int2); |
434 | 0 | else |
435 | 0 | vsp[-1].value.i = int1 - int2; |
436 | 0 | } else { |
437 | | /* +ve minus -ve = +ve plus +ve, can overflow a *signed* int, but not an unsigned int */ |
438 | 0 | u1 = int1 + ((unsigned int)(~int2) + 1); |
439 | 0 | if (u1 > (unsigned int)max_int) |
440 | 0 | store_float(vsp - 1, (double)int1 - int2); |
441 | 0 | else |
442 | 0 | vsp[-1].value.i = int1 - int2; |
443 | 0 | } |
444 | 0 | } |
445 | 0 | --vsp; continue; |
446 | 3.29M | } |
447 | 12.6M | case PtCr_sub: |
448 | 12.6M | vsp[-1].value.f -= vsp->value.f; |
449 | 12.6M | --vsp; continue; |
450 | 5 | case PtCr_truncate: |
451 | 5 | vsp->value.f = (vsp->value.f < 0 ? ceil(vsp->value.f) : |
452 | 5 | floor(vsp->value.f)); |
453 | 5 | continue; |
454 | 0 | case PtCr_xor: |
455 | 0 | vsp[-1].value.i ^= vsp->value.i; |
456 | 0 | --vsp; continue; |
457 | | |
458 | | /* Boolean operators */ |
459 | | |
460 | 0 | #define DO_REL(rel, m)\ |
461 | 3.59M | vsp[-1].value.i = vsp[-1].value.m rel vsp->value.m |
462 | | |
463 | 0 | case PtCr_eq_int: |
464 | 0 | DO_REL(==, i); |
465 | 0 | goto rel; |
466 | 17 | case PtCr_ge_int: |
467 | 17 | DO_REL(>=, i); |
468 | 17 | goto rel; |
469 | 46 | case PtCr_ge: |
470 | 46 | DO_REL(>=, f); |
471 | 46 | goto rel; |
472 | 336 | case PtCr_gt_int: |
473 | 336 | DO_REL(>, i); |
474 | 336 | goto rel; |
475 | 112 | case PtCr_gt: |
476 | 112 | DO_REL(>, f); |
477 | 112 | goto rel; |
478 | 0 | case PtCr_le_int: |
479 | 0 | DO_REL(<=, i); |
480 | 0 | goto rel; |
481 | 298k | case PtCr_le: |
482 | 298k | DO_REL(<=, f); |
483 | 298k | goto rel; |
484 | 0 | case PtCr_lt_int: |
485 | 0 | DO_REL(<, i); |
486 | 0 | goto rel; |
487 | 3.29M | case PtCr_lt: |
488 | 3.29M | DO_REL(<, f); |
489 | 3.29M | goto rel; |
490 | 0 | case PtCr_ne_int: |
491 | 0 | DO_REL(!=, i); |
492 | 0 | goto rel; |
493 | 0 | case PtCr_ne: |
494 | 0 | DO_REL(!=, f); |
495 | 0 | goto rel; |
496 | 0 | case PtCr_eq: |
497 | 0 | DO_REL(==, f); |
498 | 3.59M | rel: |
499 | 3.59M | vsp[-1].type = CVT_BOOL; |
500 | 3.59M | --vsp; continue; |
501 | | |
502 | 0 | #undef DO_REL |
503 | | |
504 | | /* Stack operators */ |
505 | | |
506 | 298k | case PtCr_copy: |
507 | 298k | i = vsp->value.i; |
508 | 298k | n = vsp - vstack; |
509 | 298k | if (i < 0 || i >= n) |
510 | 0 | return_error(gs_error_rangecheck); |
511 | 298k | if (i > MAX_VSTACK - (n - 1)) |
512 | 0 | return_error(gs_error_limitcheck); |
513 | 298k | memcpy(vsp, vsp - i, i * sizeof(*vsp)); |
514 | 298k | vsp += i - 1; |
515 | 298k | continue; |
516 | 13.0M | case PtCr_dup: |
517 | 13.0M | vsp[1] = *vsp; |
518 | 13.0M | goto push; |
519 | 15.4M | case PtCr_exch: |
520 | 15.4M | vstack[MAX_VSTACK] = *vsp; |
521 | 15.4M | *vsp = vsp[-1]; |
522 | 15.4M | vsp[-1] = vstack[MAX_VSTACK]; |
523 | 15.4M | continue; |
524 | 522k | case PtCr_index: |
525 | 522k | i = vsp->value.i; |
526 | 522k | if (i < 0 || i >= vsp - vstack - 1) |
527 | 0 | return_error(gs_error_rangecheck); |
528 | 522k | *vsp = vsp[-i - 1]; |
529 | 522k | continue; |
530 | 8.94M | case PtCr_pop: |
531 | 8.94M | --vsp; |
532 | 8.94M | continue; |
533 | 7.22M | case PtCr_roll: |
534 | 7.22M | n = vsp[-1].value.i; |
535 | 7.22M | i = vsp->value.i; |
536 | 7.22M | if (n < 0 || n > vsp - vstack - 2) |
537 | 0 | return_error(gs_error_rangecheck); |
538 | | /* We don't bother to do this efficiently. */ |
539 | 17.3M | for (; i > 0; i--) { |
540 | 10.1M | memmove(vsp - n, vsp - (n + 1), n * sizeof(*vsp)); |
541 | 10.1M | vsp[-(n + 1)] = vsp[-1]; |
542 | 10.1M | } |
543 | 8.87M | for (; i < 0; i++) { |
544 | 1.65M | vsp[-1] = vsp[-(n + 1)]; |
545 | 1.65M | memmove(vsp - (n + 1), vsp - n, n * sizeof(*vsp)); |
546 | 1.65M | } |
547 | 7.22M | vsp -= 2; |
548 | 7.22M | continue; |
549 | | |
550 | | /* Constants */ |
551 | | |
552 | 28.5M | case PtCr_byte: |
553 | 28.5M | vsp[1].value.i = *p++, vsp[1].type = CVT_INT; |
554 | 28.5M | goto push; |
555 | 7.53M | case PtCr_int /* native */: |
556 | 7.53M | memcpy(&vsp[1].value.i, p, sizeof(int)); |
557 | 7.53M | vsp[1].type = CVT_INT; |
558 | 7.53M | p += sizeof(int); |
559 | 7.53M | goto push; |
560 | 6.97M | case PtCr_float /* native */: |
561 | 6.97M | memcpy(&vsp[1].value.f, p, sizeof(float)); |
562 | 6.97M | vsp[1].type = CVT_FLOAT; |
563 | 6.97M | p += sizeof(float); |
564 | 6.97M | goto push; |
565 | 0 | case PtCr_true: |
566 | 0 | vsp[1].value.i = true, vsp[1].type = CVT_BOOL; |
567 | 0 | goto push; |
568 | 0 | case PtCr_false: |
569 | 0 | vsp[1].value.i = false, vsp[1].type = CVT_BOOL; |
570 | 56.1M | push: |
571 | 56.1M | if (vsp == &vstack[MAX_VSTACK]) |
572 | 0 | return_error(gs_error_limitcheck); |
573 | 56.1M | ++vsp; |
574 | 56.1M | continue; |
575 | | |
576 | | /* Special */ |
577 | | |
578 | 3.59M | case PtCr_if: |
579 | 3.59M | if ((vsp--)->value.i) { /* value is true, execute body */ |
580 | 3.04M | p += 2; |
581 | 3.04M | continue; |
582 | 3.04M | } |
583 | | /* falls through */ |
584 | 698k | case PtCr_else: |
585 | 698k | p += 2 + (p[0] << 8) + p[1]; /* skip the past body */ |
586 | 698k | continue; |
587 | 6.37M | case PtCr_return: |
588 | 6.37M | goto fin; |
589 | 0 | case PtCr_repeat: |
590 | 0 | repeat_nesting_level++; |
591 | 0 | repeat_count[repeat_nesting_level] = vsp->value.i; |
592 | 0 | repeat_proc_size[repeat_nesting_level] = 1 + (p[0] << 8) + p[1]; /* body size */ |
593 | 0 | --vsp; /* pop the counter */ |
594 | 0 | p += 3 + (p[0] <<8) + p[1]; /* advance just past the repeat_end */ |
595 | | /* falls through */ |
596 | 0 | case PtCr_repeat_end: |
597 | 0 | if (repeat_nesting_level < 0) |
598 | 0 | return_error(gs_error_rangecheck); |
599 | | |
600 | 0 | if ((repeat_count[repeat_nesting_level])-- <= 0) |
601 | 0 | repeat_nesting_level--; |
602 | 0 | else |
603 | 0 | p -= repeat_proc_size[repeat_nesting_level]; |
604 | 0 | continue; |
605 | 162M | } |
606 | 162M | } |
607 | 6.37M | fin: |
608 | 6.37M | { /* Following Acrobat, take the desired number of parameters */ |
609 | | /* from the top of stack and ignore the rest. Bug 702950. */ |
610 | 6.37M | int extra_ops = vsp - vstack - pfn->params.n; |
611 | 6.37M | if (extra_ops < 0) |
612 | 63 | return_error(gs_error_rangecheck); |
613 | 25.1M | for (i = 0; i < pfn->params.n; ++i) { |
614 | 18.7M | switch (vstack[i + 1 + extra_ops].type) { |
615 | 15.1k | case CVT_INT: |
616 | 15.1k | out[i] = (float)vstack[i + 1 + extra_ops].value.i; |
617 | 15.1k | break; |
618 | 18.7M | case CVT_FLOAT: |
619 | 18.7M | out[i] = vstack[i + 1 + extra_ops].value.f; |
620 | 18.7M | break; |
621 | 0 | default: |
622 | 0 | return_error(gs_error_typecheck); |
623 | 18.7M | } |
624 | 18.7M | } |
625 | 6.37M | } |
626 | 6.37M | return 0; |
627 | 6.37M | } |
628 | | |
629 | | /* Test whether a PostScript Calculator function is monotonic. */ |
630 | | static int |
631 | | fn_PtCr_is_monotonic(const gs_function_t * pfn_common, |
632 | | const float *lower, const float *upper, uint *mask) |
633 | 0 | { |
634 | | /* |
635 | | * No reasonable way to tell. Eventually we should check for |
636 | | * functions consisting of only stack-manipulating operations, |
637 | | * since these may be common for DeviceN color spaces and *are* |
638 | | * monotonic. |
639 | | */ |
640 | 0 | *mask = 0x49249249; |
641 | 0 | return 0; |
642 | 0 | } |
643 | | |
644 | | /* Write the function definition in symbolic form on a stream. */ |
645 | | static int |
646 | | calc_put_ops(stream *s, const byte *ops, uint size) |
647 | 1.57k | { |
648 | 1.57k | const byte *p; |
649 | | |
650 | 1.57k | spputc(s, '{'); |
651 | 13.1k | for (p = ops; p < ops + size; ) |
652 | 11.5k | switch (*p++) { |
653 | 3.30k | case PtCr_byte: |
654 | 3.30k | pprintd1(s, "%d ", *p++); |
655 | 3.30k | break; |
656 | 620 | case PtCr_int: { |
657 | 620 | int i; |
658 | | |
659 | 620 | memcpy(&i, p, sizeof(int)); |
660 | 620 | pprintd1(s, "%d ", i); |
661 | 620 | p += sizeof(int); |
662 | 620 | break; |
663 | 0 | } |
664 | 3.08k | case PtCr_float: { |
665 | 3.08k | float f; |
666 | | |
667 | 3.08k | memcpy(&f, p, sizeof(float)); |
668 | 3.08k | pprintg1(s, "%g ", f); |
669 | 3.08k | p += sizeof(float); |
670 | 3.08k | break; |
671 | 0 | } |
672 | 0 | case PtCr_true: |
673 | 0 | stream_puts(s, "true "); |
674 | 0 | break; |
675 | 0 | case PtCr_false: |
676 | 0 | stream_puts(s, "false "); |
677 | 0 | break; |
678 | 166 | case PtCr_if: { |
679 | 166 | int skip = (p[0] << 8) + p[1]; |
680 | 166 | int code; |
681 | | |
682 | 166 | code = calc_put_ops(s, p += 2, skip); |
683 | 166 | p += skip; |
684 | 166 | if (code < 0) |
685 | 0 | return code; |
686 | 166 | if (code > 0) { /* else */ |
687 | 0 | skip = (p[-2] << 8) + p[-1]; |
688 | 0 | code = calc_put_ops(s, p, skip); |
689 | 0 | p += skip; |
690 | 0 | if (code < 0) |
691 | 0 | return code; |
692 | 0 | stream_puts(s, " ifelse "); |
693 | 0 | } else |
694 | 166 | stream_puts(s, " if "); |
695 | 166 | break; |
696 | 166 | } |
697 | 166 | case PtCr_else: |
698 | 0 | if (p != ops + size - 2) |
699 | 0 | return_error(gs_error_rangecheck); |
700 | 0 | spputc(s, '}'); |
701 | 0 | return 1; |
702 | | /*case PtCr_return:*/ /* not possible */ |
703 | 0 | case PtCr_repeat: /* We shouldn't encounter this, but just in case */ |
704 | 0 | case PtCr_repeat_end: |
705 | 0 | return_error(gs_error_rangecheck); |
706 | 4.37k | default: { /* must be < PtCr_NUM_OPS */ |
707 | 4.37k | static const char *const op_names[] = { |
708 | | /* Keep this consistent with opcodes in gsfunc4.h! */ |
709 | 4.37k | "abs", "add", "and", "atan", "bitshift", |
710 | 4.37k | "ceiling", "cos", "cvi", "cvr", "div", "exp", |
711 | 4.37k | "floor", "idiv", "ln", "log", "mod", "mul", |
712 | 4.37k | "neg", "not", "or", "round", "sin", "sqrt", "sub", |
713 | 4.37k | "truncate", "xor", |
714 | 4.37k | "eq", "ge", "gt", "le", "lt", "ne", |
715 | 4.37k | "copy", "dup", "exch", "index", "pop", "roll" |
716 | 4.37k | }; |
717 | | |
718 | 4.37k | pprints1(s, "%s ", op_names[p[-1]]); |
719 | 4.37k | } |
720 | 11.5k | } |
721 | 1.57k | spputc(s, '}'); |
722 | 1.57k | return 0; |
723 | 1.57k | } |
724 | | static int |
725 | | calc_put(stream *s, const gs_function_PtCr_t *pfn) |
726 | 1.40k | { |
727 | 1.40k | calc_put_ops(s, pfn->params.ops.data, pfn->params.ops.size - 1); |
728 | 1.40k | return 0; |
729 | 1.40k | } |
730 | | |
731 | | /* Access the symbolic definition as a DataSource. */ |
732 | | static int |
733 | | calc_access(const gs_data_source_t *psrc, ulong start, uint length, |
734 | | byte *buf, const byte **ptr) |
735 | 726 | { |
736 | 726 | const gs_function_PtCr_t *const pfn = |
737 | 726 | (const gs_function_PtCr_t *) |
738 | 726 | ((const char *)psrc - offset_of(gs_function_PtCr_t, data_source)); |
739 | | /* |
740 | | * The caller wants a specific substring of the symbolic definition. |
741 | | * Generate the entire definition, using a SubFileDecode filter (in an |
742 | | * output pipeline!) to extract the substring. This is very |
743 | | * inefficient, but this code is rarely used, and almost never actually |
744 | | * has to break up the definition into pieces to fit in the caller's |
745 | | * buffer. |
746 | | */ |
747 | 726 | stream_SFD_state st; |
748 | 726 | stream ds, bs; |
749 | 726 | byte dbuf[200]; /* arbitrary */ |
750 | 726 | const stream_template *const templat = &s_SFD_template; |
751 | | |
752 | | /* Set up the stream that writes into the buffer. */ |
753 | 726 | s_init(&bs, NULL); |
754 | 726 | swrite_string(&bs, buf, length); |
755 | | /* Set up the SubFileDecode stream. */ |
756 | 726 | s_init(&ds, NULL); |
757 | 726 | s_init_state((stream_state *)&st, templat, NULL); |
758 | 726 | templat->set_defaults((stream_state *)&st); |
759 | 726 | st.skip_count = start; |
760 | 726 | s_init_filter(&ds, (stream_state *)&st, dbuf, sizeof(dbuf), &bs); |
761 | 726 | calc_put(&ds, pfn); |
762 | 726 | sclose(&ds); |
763 | 726 | if (ptr) |
764 | 726 | *ptr = buf; |
765 | 726 | return 0; |
766 | 726 | } |
767 | | |
768 | | /* Return PostScript Calculator function information. */ |
769 | | static void |
770 | | fn_PtCr_get_info(const gs_function_t *pfn_common, gs_function_info_t *pfi) |
771 | 682 | { |
772 | 682 | const gs_function_PtCr_t *const pfn = |
773 | 682 | (const gs_function_PtCr_t *)pfn_common; |
774 | | |
775 | 682 | gs_function_get_info_default(pfn_common, pfi); |
776 | 682 | pfi->DataSource = &pfn->data_source; |
777 | 682 | { |
778 | 682 | stream s; |
779 | | |
780 | 682 | s_init(&s, NULL); |
781 | 682 | swrite_position_only(&s); |
782 | 682 | calc_put(&s, pfn); |
783 | 682 | pfi->data_size = stell(&s); |
784 | 682 | } |
785 | 682 | } |
786 | | |
787 | | /* Make a scaled copy of a PostScript Calculator function. */ |
788 | | static int |
789 | | fn_PtCr_make_scaled(const gs_function_PtCr_t *pfn, gs_function_PtCr_t **ppsfn, |
790 | | const gs_range_t *pranges, gs_memory_t *mem) |
791 | 0 | { |
792 | 0 | gs_function_PtCr_t *psfn = |
793 | 0 | gs_alloc_struct(mem, gs_function_PtCr_t, &st_function_PtCr, |
794 | 0 | "fn_PtCr_make_scaled"); |
795 | | /* We are adding {<int> 1 roll <float> mul <float> add} for each output. */ |
796 | 0 | int n = pfn->params.n; |
797 | 0 | uint opsize = pfn->params.ops.size + (9 + 2 * sizeof(float)) * n; |
798 | 0 | byte *ops = gs_alloc_string(mem, opsize, "fn_PtCr_make_scaled(ops)"); |
799 | 0 | byte *p; |
800 | 0 | int code, i; |
801 | |
|
802 | 0 | if (psfn == 0 || ops == 0) { |
803 | 0 | gs_free_string(mem, ops, opsize, "fn_PtCr_make_scaled(ops)"); |
804 | 0 | gs_free_object(mem, psfn, "fn_PtCr_make_scaled"); |
805 | 0 | return_error(gs_error_VMerror); |
806 | 0 | } |
807 | 0 | psfn->params = pfn->params; |
808 | 0 | psfn->params.ops.data = ops; |
809 | 0 | psfn->params.ops.size = opsize; |
810 | 0 | psfn->data_source = pfn->data_source; |
811 | 0 | code = fn_common_scale((gs_function_t *)psfn, (const gs_function_t *)pfn, |
812 | 0 | pranges, mem); |
813 | 0 | if (code < 0) { |
814 | 0 | gs_function_free((gs_function_t *)psfn, true, mem); |
815 | 0 | return code; |
816 | 0 | } |
817 | 0 | memcpy(ops, pfn->params.ops.data, pfn->params.ops.size - 1); /* minus return */ |
818 | 0 | p = ops + pfn->params.ops.size - 1; |
819 | 0 | for (i = n; --i >= 0; ) { |
820 | 0 | float base = pranges[i].rmin; |
821 | 0 | float factor = pranges[i].rmax - base; |
822 | |
|
823 | 0 | if (factor != 1) { |
824 | 0 | p[0] = PtCr_float; memcpy(p + 1, &factor, sizeof(float)); |
825 | 0 | p += 1 + sizeof(float); |
826 | 0 | *p++ = PtCr_mul; |
827 | 0 | } |
828 | 0 | if (base != 0) { |
829 | 0 | p[0] = PtCr_float; memcpy(p + 1, &base, sizeof(float)); |
830 | 0 | p += 1 + sizeof(float); |
831 | 0 | *p++ = PtCr_add; |
832 | 0 | } |
833 | 0 | if (n != 1) { |
834 | 0 | p[0] = PtCr_byte; p[1] = (byte)n; |
835 | 0 | p[2] = PtCr_byte; p[3] = 1; |
836 | 0 | p[4] = PtCr_roll; |
837 | 0 | p += 5; |
838 | 0 | } |
839 | 0 | } |
840 | 0 | *p++ = PtCr_return; |
841 | 0 | psfn->params.ops.size = p - ops; |
842 | 0 | psfn->params.ops.data = |
843 | 0 | gs_resize_string(mem, ops, opsize, psfn->params.ops.size, |
844 | 0 | "fn_PtCr_make_scaled"); |
845 | 0 | *ppsfn = psfn; |
846 | 0 | return 0; |
847 | 0 | } |
848 | | |
849 | | /* Free the parameters of a PostScript Calculator function. */ |
850 | | void |
851 | | gs_function_PtCr_free_params(gs_function_PtCr_params_t * params, gs_memory_t * mem) |
852 | 45.4k | { |
853 | 45.4k | gs_free_const_string(mem, params->ops.data, params->ops.size, "ops"); |
854 | 45.4k | params->ops.data = NULL; |
855 | 45.4k | params->ops.size = 0; |
856 | 45.4k | fn_common_free_params((gs_function_params_t *) params, mem); |
857 | 45.4k | } |
858 | | |
859 | | /* Serialize. */ |
860 | | static int |
861 | | gs_function_PtCr_serialize(const gs_function_t * pfn, stream *s) |
862 | 10.0k | { |
863 | 10.0k | uint n; |
864 | 10.0k | const gs_function_PtCr_params_t * p = (const gs_function_PtCr_params_t *)&pfn->params; |
865 | 10.0k | int code = fn_common_serialize(pfn, s); |
866 | | |
867 | 10.0k | if (code < 0) |
868 | 0 | return code; |
869 | 10.0k | code = sputs(s, (const byte *)&p->ops.size, sizeof(p->ops.size), &n); |
870 | 10.0k | if (code < 0) |
871 | 0 | return code; |
872 | 10.0k | return sputs(s, p->ops.data, p->ops.size, &n); |
873 | 10.0k | } |
874 | | |
875 | | /* Allocate and initialize a PostScript Calculator function. */ |
876 | | int |
877 | | gs_function_PtCr_init(gs_function_t ** ppfn, |
878 | | const gs_function_PtCr_params_t * params, gs_memory_t * mem) |
879 | 51.5k | { |
880 | 51.5k | static const gs_function_head_t function_PtCr_head = { |
881 | 51.5k | function_type_PostScript_Calculator, |
882 | 51.5k | { |
883 | 51.5k | (fn_evaluate_proc_t) fn_PtCr_evaluate, |
884 | 51.5k | (fn_is_monotonic_proc_t) fn_PtCr_is_monotonic, |
885 | 51.5k | (fn_get_info_proc_t) fn_PtCr_get_info, |
886 | 51.5k | fn_common_get_params, |
887 | 51.5k | (fn_make_scaled_proc_t) fn_PtCr_make_scaled, |
888 | 51.5k | (fn_free_params_proc_t) gs_function_PtCr_free_params, |
889 | 51.5k | fn_common_free, |
890 | 51.5k | (fn_serialize_proc_t) gs_function_PtCr_serialize, |
891 | 51.5k | } |
892 | 51.5k | }; |
893 | 51.5k | int code; |
894 | | |
895 | 51.5k | *ppfn = 0; /* in case of error */ |
896 | 51.5k | code = fn_check_mnDR((const gs_function_params_t *)params, |
897 | 51.5k | params->m, params->n); |
898 | 51.5k | if (code < 0) |
899 | 28 | return code; |
900 | 51.5k | if (params->m > MAX_VSTACK || params->n > MAX_VSTACK) |
901 | 0 | return_error(gs_error_limitcheck); |
902 | | /* |
903 | | * Pre-validate the operation string to reduce evaluation overhead. |
904 | | */ |
905 | 51.5k | { |
906 | 51.5k | const byte *p = params->ops.data; |
907 | | |
908 | 1.61M | for (; *p != PtCr_return; ++p) |
909 | 1.56M | switch ((gs_PtCr_opcode_t)*p) { |
910 | 323k | case PtCr_byte: |
911 | 323k | ++p; break; |
912 | 26.5k | case PtCr_int: |
913 | 26.5k | p += sizeof(int); break; |
914 | 84.9k | case PtCr_float: |
915 | 84.9k | p += sizeof(float); break; |
916 | 0 | case PtCr_repeat: |
917 | 37.9k | case PtCr_if: |
918 | 75.3k | case PtCr_else: |
919 | 75.3k | p += 2; |
920 | 75.3k | case PtCr_repeat_end: |
921 | 75.3k | case PtCr_true: |
922 | 75.3k | case PtCr_false: |
923 | 75.3k | break; |
924 | 1.05M | default: |
925 | 1.05M | if (*p >= PtCr_NUM_OPS) |
926 | 0 | return_error(gs_error_rangecheck); |
927 | 1.56M | } |
928 | 51.5k | if (p != params->ops.data + params->ops.size - 1) |
929 | 0 | return_error(gs_error_rangecheck); |
930 | 51.5k | } |
931 | 51.5k | { |
932 | 51.5k | gs_function_PtCr_t *pfn = |
933 | 51.5k | gs_alloc_struct(mem, gs_function_PtCr_t, &st_function_PtCr, |
934 | 51.5k | "gs_function_PtCr_init"); |
935 | | |
936 | 51.5k | if (pfn == 0) |
937 | 0 | return_error(gs_error_VMerror); |
938 | 51.5k | pfn->params = *params; |
939 | | /* |
940 | | * We claim to have a DataSource, in order to write the function |
941 | | * definition in symbolic form for embedding in PDF files. |
942 | | * ****** THIS IS A HACK. ****** |
943 | | */ |
944 | 51.5k | data_source_init_string2(&pfn->data_source, NULL, 0); |
945 | 51.5k | pfn->data_source.access = calc_access; |
946 | 51.5k | pfn->head = function_PtCr_head; |
947 | 51.5k | *ppfn = (gs_function_t *) pfn; |
948 | 51.5k | } |
949 | 0 | return 0; |
950 | 51.5k | } |