]>
Commit | Line | Data |
---|---|---|
b5cb0608 | 1 | /* |
2 | Copyright 2001 by Easy Software Products. | |
3 | Copyright 1997, 1998 Aladdin Enterprises. All rights reserved. | |
caddbb58 | 4 | |
5 | This file is part of GNU Ghostscript. | |
6 | ||
7 | GNU Ghostscript is distributed in the hope that it will be useful, but | |
8 | WITHOUT ANY WARRANTY. No author or distributor accepts responsibility | |
9 | to anyone for the consequences of using it or for whether it serves any | |
10 | particular purpose or works at all, unless he says so in writing. Refer | |
11 | to the GNU General Public License for full details. | |
12 | ||
13 | Everyone is granted permission to copy, modify and redistribute GNU | |
14 | Ghostscript, but only under the conditions described in the GNU General | |
15 | Public License. A copy of this license is supposed to have been given | |
16 | to you along with GNU Ghostscript so you can know your rights and | |
17 | responsibilities. It should be in a file named COPYING. Among other | |
18 | things, the copyright notice and this notice must be preserved on all | |
19 | copies. | |
20 | ||
21 | Aladdin Enterprises supports the work of the GNU Project, but is not | |
22 | affiliated with the Free Software Foundation or the GNU Project. GNU | |
23 | Ghostscript, as distributed by Aladdin Enterprises, does not require any | |
24 | GNU software to build or run it. | |
25 | */ | |
26 | ||
b5cb0608 | 27 | /*$Id: zfunc.c,v 1.1.2.1 2001/05/13 18:38:33 mike Exp $ */ |
caddbb58 | 28 | /* Generic PostScript language interface to Functions */ |
29 | #include "memory_.h" | |
30 | #include "ghost.h" | |
31 | #include "oper.h" | |
32 | #include "gsfunc.h" | |
33 | #include "gsstruct.h" | |
34 | #include "ialloc.h" | |
35 | #include "idict.h" | |
36 | #include "idparam.h" | |
37 | #include "ifunc.h" | |
38 | #include "store.h" | |
39 | ||
40 | /* Define the maximum depth of nesting of subsidiary functions. */ | |
41 | #define MAX_SUB_FUNCTION_DEPTH 3 | |
42 | ||
43 | /* Define the table of build procedures. */ | |
44 | build_function_proc((*build_function_procs[5])) = { | |
45 | build_function_undefined, build_function_undefined, build_function_undefined, | |
46 | build_function_undefined, build_function_undefined | |
47 | }; | |
48 | ||
49 | int | |
50 | build_function_undefined(const_os_ptr op, const gs_function_params_t * mnDR, | |
51 | int depth, gs_function_t ** ppfn) | |
52 | { | |
53 | return_error(e_rangecheck); | |
54 | } | |
55 | ||
56 | /* GC descriptors */ | |
57 | gs_private_st_ptr(st_function_ptr, gs_function_t *, "gs_function_t *", | |
58 | function_ptr_enum_ptrs, function_ptr_reloc_ptrs); | |
59 | gs_private_st_element(st_function_ptr_element, gs_function_t *, | |
60 | "gs_function_t *[]", function_ptr_element_enum_ptrs, | |
61 | function_ptr_element_reloc_ptrs, st_function_ptr); | |
62 | ||
63 | /* ------ Operators ------ */ | |
64 | ||
65 | private int zexecfunction(P1(os_ptr op)); | |
66 | ||
67 | /* <dict> .buildfunction <function_struct> */ | |
68 | private int | |
69 | zbuildfunction(os_ptr op) | |
70 | { | |
71 | gs_function_t *pfn; | |
72 | ref cref; /* closure */ | |
73 | int code; | |
74 | ||
75 | code = ialloc_ref_array(&cref, a_executable | a_execute, 2, | |
76 | ".buildfunction"); | |
77 | if (code < 0) | |
78 | return code; | |
79 | code = fn_build_function(op, &pfn); | |
80 | if (code < 0) { | |
81 | ifree_ref_array(&cref, ".buildfunction"); | |
82 | return code; | |
83 | } | |
84 | make_istruct_new(cref.value.refs, a_executable | a_execute, pfn); | |
85 | make_oper_new(cref.value.refs + 1, 0, zexecfunction); | |
86 | ref_assign(op, &cref); | |
87 | return 0; | |
88 | } | |
89 | ||
90 | /* <in1> ... <function_struct> %execfunction <out1> ... */ | |
91 | private int | |
92 | zexecfunction(os_ptr op) | |
93 | { /* | |
94 | * Since this operator's name begins with %, the name is not defined | |
95 | * in systemdict. The only place this operator can ever appear is | |
96 | * in the execute-only closure created by .buildfunction. | |
97 | * Therefore, in principle it is unnecessary to check the argument. | |
98 | * However, we do a little checking anyway just on general | |
99 | * principles. Note that since the argument may be an instance of | |
100 | * any subclass of gs_function_t, we currently have no way to check | |
101 | * its type. | |
102 | */ | |
103 | if (!r_is_struct(op) || | |
104 | r_has_masked_attrs(op, a_executable | a_execute, a_all) | |
105 | ) | |
106 | return_error(e_typecheck); | |
107 | { | |
108 | gs_function_t *pfn = (gs_function_t *) op->value.pstruct; | |
109 | int m = pfn->params.m, n = pfn->params.n; | |
110 | int diff = n - (m + 1); | |
111 | ||
112 | if (diff > 0) | |
113 | check_ostack(diff); | |
114 | { | |
115 | float *in = (float *)ialloc_byte_array(m, sizeof(float), | |
116 | "%execfunction(in)"); | |
117 | float *out = (float *)ialloc_byte_array(n, sizeof(float), | |
118 | "%execfunction(out)"); | |
119 | int code; | |
120 | ||
121 | if (in == 0 || out == 0) | |
122 | code = gs_note_error(e_VMerror); | |
123 | else if ((code = float_params(op - 1, m, in)) < 0 || | |
124 | (code = gs_function_evaluate(pfn, in, out)) < 0 | |
125 | ) | |
126 | DO_NOTHING; | |
127 | else { | |
128 | if (diff > 0) | |
b5cb0608 | 129 | push(diff) /* can't fail */ /* MRS: No trailing ; */ |
caddbb58 | 130 | else if (diff < 0) { |
131 | pop(-diff); | |
132 | op = osp; | |
133 | } | |
134 | code = make_floats(op + 1 - n, out, n); | |
135 | } | |
136 | ifree_object(out, "%execfunction(out)"); | |
137 | ifree_object(in, "%execfunction(in)"); | |
138 | return code; | |
139 | } | |
140 | } | |
141 | } | |
142 | ||
143 | /* ------ Procedures ------ */ | |
144 | ||
145 | /* Build a function structure from a PostScript dictionary. */ | |
146 | int | |
147 | fn_build_sub_function(const ref * op, gs_function_t ** ppfn, int depth) | |
148 | { | |
149 | int code, type; | |
150 | gs_function_params_t params; | |
151 | ||
152 | if (depth > MAX_SUB_FUNCTION_DEPTH) | |
153 | return_error(e_limitcheck); | |
154 | check_type(*op, t_dictionary); | |
155 | code = dict_int_param(op, "FunctionType", 0, | |
156 | countof(build_function_procs) - 1, -1, &type); | |
157 | if (code < 0) | |
158 | return code; | |
159 | /* Collect parameters common to all function types. */ | |
160 | params.Domain = 0; | |
161 | params.Range = 0; | |
162 | code = fn_build_float_array(op, "Domain", true, true, ¶ms.Domain); | |
163 | if (code < 0) | |
164 | goto fail; | |
165 | params.m = code >> 1; | |
166 | code = fn_build_float_array(op, "Range", false, true, ¶ms.Range); | |
167 | if (code < 0) | |
168 | goto fail; | |
169 | params.n = code >> 1; | |
170 | /* Finish building the function. */ | |
171 | /* If this fails, it will free all the parameters. */ | |
172 | return (*build_function_procs[type]) (op, ¶ms, depth + 1, ppfn); | |
173 | fail: | |
174 | ifree_object((void *)params.Range, "Range"); /* break const */ | |
175 | ifree_object((void *)params.Domain, "Domain"); /* break const */ | |
176 | return code; | |
177 | } | |
178 | ||
179 | /* Allocate an array of function objects. */ | |
180 | int | |
181 | ialloc_function_array(uint count, gs_function_t *** pFunctions) | |
182 | { | |
183 | gs_function_t **ptr; | |
184 | ||
185 | if (count == 0) | |
186 | return_error(e_rangecheck); | |
187 | ptr = ialloc_struct_array(count, gs_function_t *, | |
188 | &st_function_ptr_element, "Functions"); | |
189 | if (ptr == 0) | |
190 | return_error(e_VMerror); | |
191 | memset(ptr, 0, sizeof(*ptr) * count); | |
192 | *pFunctions = ptr; | |
193 | return 0; | |
194 | } | |
195 | ||
196 | /* | |
197 | * Collect a heap-allocated array of floats. If the key is missing, set | |
198 | * *pparray = 0 and return 0; otherwise set *pparray and return the number | |
199 | * of elements. Note that 0-length arrays are acceptable, so if the value | |
200 | * returned is 0, the caller must check whether *pparray == 0. | |
201 | */ | |
202 | int | |
203 | fn_build_float_array(const ref * op, const char *kstr, bool required, | |
204 | bool even, const float **pparray) | |
205 | { | |
206 | ref *par; | |
207 | int code; | |
208 | ||
209 | *pparray = 0; | |
210 | if (dict_find_string(op, kstr, &par) <= 0) | |
211 | return (required ? gs_note_error(e_rangecheck) : 0); | |
212 | if (!r_is_array(par)) | |
213 | return_error(e_typecheck); | |
214 | { | |
215 | uint size = r_size(par); | |
216 | float *ptr = (float *)ialloc_byte_array(size, sizeof(float), kstr); | |
217 | ||
218 | if (ptr == 0) | |
219 | return_error(e_VMerror); | |
220 | code = dict_float_array_param(op, kstr, size, ptr, NULL); | |
221 | if (code < 0 || (even && (code & 1) != 0)) { | |
222 | ifree_object(ptr, kstr); | |
223 | return(code < 0 ? code : gs_note_error(e_rangecheck)); | |
224 | } | |
225 | *pparray = ptr; | |
226 | } | |
227 | return code; | |
228 | } | |
229 | ||
230 | /* ------ Initialization procedure ------ */ | |
231 | ||
232 | const op_def zfunc_op_defs[] = | |
233 | { | |
234 | {"1.buildfunction", zbuildfunction}, | |
235 | {"1%execfunction", zexecfunction}, | |
236 | op_def_end(0) | |
237 | }; |