Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
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
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, &params.Domain, mem);
232
    if (code < 0)
233
	goto fail;
234
    params.m = code >> 1;
235
    code = fn_build_float_array(op, "Range", false, true, &params.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, &params, 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
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
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 *
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
};