1 /* Copyright (C) 1997, 2000 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: zfunc.c,v 1.14 2004/08/04 19:36:13 stefan Exp $ */
18 /* Generic PostScript language interface to Functions */
19 #include "memory_.h"
20 #include "ghost.h"
21 #include "oper.h"
22 #include "gscdefs.h"
23 #include "gsfunc.h"
24 #include "gsstruct.h"
25 #include "ialloc.h"
26 #include "idict.h"
27 #include "idparam.h"
28 #include "ifunc.h"
29 #include "store.h"
30
31 /*#define TEST*/
32
33 /* Define the maximum depth of nesting of subsidiary functions. */
34 #define MAX_SUB_FUNCTION_DEPTH 3
35
36 /* ------ Operators ------ */
37
38 /* Create a function procedure from a function structure. */
39 private int
make_function_proc(i_ctx_t * i_ctx_p,ref * op,gs_function_t * pfn)40 make_function_proc(i_ctx_t *i_ctx_p, ref *op, gs_function_t *pfn)
41 {
42 ref cref; /* closure */
43 int code;
44
45 code = ialloc_ref_array(&cref, a_executable | a_execute, 2,
46 ".buildfunction");
47 if (code < 0)
48 return code;
49 make_istruct_new(cref.value.refs, a_executable | a_execute, pfn);
50 make_oper_new(cref.value.refs + 1, 0, zexecfunction);
51 ref_assign(op, &cref);
52 return 0;
53 }
54
55 /* <dict> .buildfunction <function_proc> */
56 private int
zbuildfunction(i_ctx_t * i_ctx_p)57 zbuildfunction(i_ctx_t *i_ctx_p)
58 {
59 os_ptr op = osp;
60 gs_function_t *pfn;
61 int code = fn_build_function(i_ctx_p, op, &pfn, imemory);
62
63 if (code < 0)
64 return code;
65 code = make_function_proc(i_ctx_p, op, pfn);
66 if (code < 0)
67 gs_function_free(pfn, true, imemory);
68 return 0;
69 }
70
71 #ifdef TEST
72
73 /* <function_proc> <array> .scalefunction <function_proc> */
74 private int
zscalefunction(i_ctx_t * i_ctx_p)75 zscalefunction(i_ctx_t *i_ctx_p)
76 {
77 os_ptr op = osp;
78 gs_function_t *pfn;
79 gs_function_t *psfn;
80 gs_range_t *ranges;
81 int code;
82 uint i;
83
84 check_proc(op[-1]);
85 pfn = ref_function(op - 1);
86 if (pfn == 0 || !r_is_array(op))
87 return_error(e_typecheck);
88 if (r_size(op) != 2 * pfn->params.n)
89 return_error(e_rangecheck);
90 ranges = (gs_range_t *)
91 gs_alloc_byte_array(imemory, pfn->params.n, sizeof(gs_range_t),
92 "zscalefunction");
93 if (ranges == 0)
94 return_error(e_VMerror);
95 for (i = 0; i < pfn->params.n; ++i) {
96 ref rval[2];
97 float val[2];
98
99 if ((code = array_get(op, 2 * i, &rval[0])) < 0 ||
100 (code = array_get(op, 2 * i + 1, &rval[1])) < 0 ||
101 (code = float_params(rval + 1, 2, val)) < 0)
102 return code;
103 ranges[i].rmin = val[0];
104 ranges[i].rmax = val[1];
105 }
106 code = gs_function_make_scaled(pfn, &psfn, ranges, imemory);
107 gs_free_object(imemory, ranges, "zscalefunction");
108 if (code < 0 ||
109 (code = make_function_proc(i_ctx_p, op - 1, psfn)) < 0) {
110 gs_function_free(psfn, true, imemory);
111 return code;
112 }
113 pop(1);
114 return 0;
115 }
116
117 #endif /* TEST */
118
119 /* <in1> ... <function_struct> %execfunction <out1> ... */
120 int
zexecfunction(i_ctx_t * i_ctx_p)121 zexecfunction(i_ctx_t *i_ctx_p)
122 {
123 os_ptr op = osp;
124
125 /*
126 * Since this operator's name begins with %, the name is not defined
127 * in systemdict. The only place this operator can ever appear is
128 * in the execute-only closure created by .buildfunction.
129 * Therefore, in principle it is unnecessary to check the argument.
130 * However, we do a little checking anyway just on general
131 * principles. Note that since the argument may be an instance of
132 * any subclass of gs_function_t, we currently have no way to check
133 * its type.
134 */
135 if (!r_is_struct(op) ||
136 !r_has_masked_attrs(op, a_executable | a_execute, a_executable | a_all)
137 )
138 return_error(e_typecheck);
139 {
140 gs_function_t *pfn = (gs_function_t *) op->value.pstruct;
141 int m = pfn->params.m, n = pfn->params.n;
142 int diff = n - (m + 1);
143
144 if (diff > 0)
145 check_ostack(diff);
146 {
147 float params[20]; /* arbitrary size, just to avoid allocs */
148 float *in;
149 float *out;
150 int code = 0;
151
152 if (m + n <= countof(params)) {
153 in = params;
154 } else {
155 in = (float *)ialloc_byte_array(m + n, sizeof(float),
156 "%execfunction(in/out)");
157 if (in == 0)
158 code = gs_note_error(e_VMerror);
159 }
160 out = in + m;
161 if (code < 0 ||
162 (code = float_params(op - 1, m, in)) < 0 ||
163 (code = gs_function_evaluate(pfn, in, out)) < 0
164 )
165 DO_NOTHING;
166 else {
167 if (diff > 0)
168 push(diff); /* can't fail */
169 else if (diff < 0) {
170 pop(-diff);
171 op = osp;
172 }
173 code = make_floats(op + 1 - n, out, n);
174 }
175 if (in != params)
176 ifree_object(in, "%execfunction(in)");
177 return code;
178 }
179 }
180 }
181
182 /*
183 * <proc> .isencapfunction <bool>
184 *
185 * This routine checks if a given Postscript procedure is an "encapsulated"
186 * function of the type made by .buildfunction. These functions can then
187 * be executed without executing the interpreter. These functions can be
188 * executed directly from within C code inside the graphics library.
189 */
190 private int
zisencapfunction(i_ctx_t * i_ctx_p)191 zisencapfunction(i_ctx_t *i_ctx_p)
192 {
193 os_ptr op = osp;
194 gs_function_t *pfn;
195
196 check_proc(*op);
197 pfn = ref_function(op);
198 make_bool(op, pfn != NULL);
199 return 0;
200 }
201
202 /* ------ Procedures ------ */
203
204 /* Build a function structure from a PostScript dictionary. */
205 int
fn_build_function(i_ctx_t * i_ctx_p,const ref * op,gs_function_t ** ppfn,gs_memory_t * mem)206 fn_build_function(i_ctx_t *i_ctx_p, const ref * op, gs_function_t ** ppfn, gs_memory_t *mem)
207 {
208 return fn_build_sub_function(i_ctx_p, op, ppfn, 0, mem);
209 }
210 int
fn_build_sub_function(i_ctx_t * i_ctx_p,const ref * op,gs_function_t ** ppfn,int depth,gs_memory_t * mem)211 fn_build_sub_function(i_ctx_t *i_ctx_p, const ref * op, gs_function_t ** ppfn,
212 int depth, gs_memory_t *mem)
213 {
214 int code, type, i;
215 gs_function_params_t params;
216
217 if (depth > MAX_SUB_FUNCTION_DEPTH)
218 return_error(e_limitcheck);
219 check_type(*op, t_dictionary);
220 code = dict_int_param(op, "FunctionType", 0, max_int, -1, &type);
221 if (code < 0)
222 return code;
223 for (i = 0; i < build_function_type_table_count; ++i)
224 if (build_function_type_table[i].type == type)
225 break;
226 if (i == build_function_type_table_count)
227 return_error(e_rangecheck);
228 /* Collect parameters common to all function types. */
229 params.Domain = 0;
230 params.Range = 0;
231 code = fn_build_float_array(op, "Domain", true, true, ¶ms.Domain, mem);
232 if (code < 0)
233 goto fail;
234 params.m = code >> 1;
235 code = fn_build_float_array(op, "Range", false, true, ¶ms.Range, mem);
236 if (code < 0)
237 goto fail;
238 params.n = code >> 1;
239 /* Finish building the function. */
240 /* If this fails, it will free all the parameters. */
241 return (*build_function_type_table[i].proc)
242 (i_ctx_p, op, ¶ms, depth + 1, ppfn, mem);
243 fail:
244 gs_free_const_object(mem, params.Range, "Range");
245 gs_free_const_object(mem, params.Domain, "Domain");
246 return code;
247 }
248
249 /*
250 * Collect a heap-allocated array of floats. If the key is missing, set
251 * *pparray = 0 and return 0; otherwise set *pparray and return the number
252 * of elements. Note that 0-length arrays are acceptable, so if the value
253 * returned is 0, the caller must check whether *pparray == 0.
254 */
255 int
fn_build_float_array(const ref * op,const char * kstr,bool required,bool even,const float ** pparray,gs_memory_t * mem)256 fn_build_float_array(const ref * op, const char *kstr, bool required,
257 bool even, const float **pparray, gs_memory_t *mem)
258 {
259 ref *par;
260 int code;
261
262 *pparray = 0;
263 if (dict_find_string(op, kstr, &par) <= 0)
264 return (required ? gs_note_error(e_rangecheck) : 0);
265 if (!r_is_array(par))
266 return_error(e_typecheck);
267 {
268 uint size = r_size(par);
269 float *ptr = (float *)
270 gs_alloc_byte_array(mem, size, sizeof(float), kstr);
271
272 if (ptr == 0)
273 return_error(e_VMerror);
274 code = dict_float_array_check_param(mem, op, kstr, size,
275 ptr, NULL,
276 0, e_rangecheck);
277 if (code < 0 || (even && (code & 1) != 0)) {
278 gs_free_object(mem, ptr, kstr);
279 return(code < 0 ? code : gs_note_error(e_rangecheck));
280 }
281 *pparray = ptr;
282 }
283 return code;
284 }
285
286 /*
287 * Similar to fn_build_float_array() except
288 * - numeric parameter is accepted and converted to 1-element array
289 * - number of elements is not checked for even/odd
290 */
291 int
fn_build_float_array_forced(const ref * op,const char * kstr,bool required,const float ** pparray,gs_memory_t * mem)292 fn_build_float_array_forced(const ref * op, const char *kstr, bool required,
293 const float **pparray, gs_memory_t *mem)
294 {
295 ref *par;
296 int code;
297 uint size;
298 float *ptr;
299
300 *pparray = 0;
301 if (dict_find_string(op, kstr, &par) <= 0)
302 return (required ? gs_note_error(e_rangecheck) : 0);
303
304 if( r_is_array(par) )
305 size = r_size(par);
306 else if(r_type(par) == t_integer || r_type(par) == t_real)
307 size = 1;
308 else
309 return_error(e_typecheck);
310 ptr = (float *)gs_alloc_byte_array(mem, size, sizeof(float), kstr);
311
312 if (ptr == 0)
313 return_error(e_VMerror);
314 if(r_is_array(par) )
315 code = dict_float_array_check_param(mem, op, kstr,
316 size, ptr, NULL,
317 0, e_rangecheck);
318 else {
319 code = dict_float_param(op, kstr, 0., ptr); /* defailt cannot happen */
320 if( code == 0 )
321 code = 1;
322 }
323
324 if (code < 0 ) {
325 gs_free_object(mem, ptr, kstr);
326 return code;
327 }
328 *pparray = ptr;
329 return code;
330 }
331
332 /*
333 * If a PostScript object is a Function procedure, return the function
334 * object, otherwise return 0.
335 */
336 gs_function_t *
ref_function(const ref * op)337 ref_function(const ref *op)
338 {
339 if (r_has_type(op, t_array) &&
340 r_has_masked_attrs(op, a_executable | a_execute,
341 a_executable | a_all) &&
342 r_size(op) == 2 &&
343 r_has_type_attrs(op->value.refs + 1, t_operator, a_executable) &&
344 op->value.refs[1].value.opproc == zexecfunction &&
345 r_is_struct(op->value.refs) &&
346 r_has_masked_attrs(op->value.refs, a_executable | a_execute,
347 a_executable | a_all)
348 )
349 return (gs_function_t *)op->value.refs->value.pstruct;
350 return 0;
351 }
352
353 /* ------ Initialization procedure ------ */
354
355 const op_def zfunc_op_defs[] =
356 {
357 {"1.buildfunction", zbuildfunction},
358 #ifdef TEST
359 {"2.scalefunction", zscalefunction},
360 #endif /* TEST */
361 {"1%execfunction", zexecfunction},
362 {"1.isencapfunction", zisencapfunction},
363 op_def_end(0)
364 };
365