Coverage Report

Created: 2022-10-31 07:00

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