Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/psi/zfsample.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 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
/* Sample data to create a type 0 function */
18
#include "memory_.h"
19
#include "ghost.h"
20
#include "oper.h"
21
#include "gxcspace.h"
22
#include "estack.h"
23
#include "ialloc.h"
24
#include "idict.h"
25
#include "idparam.h"
26
#include "ifunc.h"
27
#include "ostack.h"
28
#include "store.h"
29
#include "gsfunc0.h"
30
#include "gscdevn.h"
31
#include "zfunc.h"
32
#include "zcolor.h"
33
34
/*
35
 * We store the data in a string.  Since the max size for a string is 64k,
36
 * we use that as our max data size.
37
 */
38
245
#define MAX_DATA_SIZE 0x10000
39
/*
40
 * We cannot handle more than  16 inputs.  Otherwise the the data will not
41
 * fit within MAX_DATA_SIZE.
42
 */
43
245
#define MAX_NUM_INPUTS 16
44
/*
45
 * This value is rather arbitrary.
46
 */
47
0
#define MAX_NUM_OUTPUTS 128
48
49
/* --- Build sampled data function --- */
50
51
/*
52
 * This structure is used to hold data required while collecting samples
53
 * for a type 0 function (sampled data).
54
 */
55
struct gs_sampled_data_enum_s {
56
    int indexes[MAX_NUM_INPUTS];
57
    int o_stack_depth;    /* used to verify stack while sampling */
58
    gs_function_t * pfn;
59
};
60
61
typedef struct gs_sampled_data_enum_s gs_sampled_data_enum;
62
63
gs_private_st_ptrs1(st_gs_sampled_data_enum, gs_sampled_data_enum,
64
                "gs_sampled_data_enum", gs_sampled_data_enum_enum_ptrs,
65
                gs_sampled_data_enum_reloc_ptrs, pfn);
66
67
/* Forward references */
68
69
static int cube_build_func0(const ref * pdict,
70
        gs_function_Sd_params_t * params, gs_memory_t *mem);
71
static int sampled_data_setup(i_ctx_t *i_ctx_p, gs_function_t *pfn,
72
        const ref * pproc, int (*finish_proc)(i_ctx_t *),
73
        gs_memory_t * mem);
74
static int sampled_data_sample(i_ctx_t *i_ctx_p);
75
static int sampled_data_continue(i_ctx_t *i_ctx_p);
76
static int sampled_data_finish(i_ctx_t *i_ctx_p);
77
78
static gs_sampled_data_enum * gs_sampled_data_enum_alloc
79
        (gs_memory_t * mem, client_name_t cname);
80
81
/*
82
 * Collect data for a type 0 (sampled data) function
83
 * <dict> .buildsampledfunction <function_struct>
84
 *
85
 * The following keys are used from the dictionary:
86
 *    Function (required)
87
 *    Domain (required)
88
 *    Range (required)
89
 *    Size (optional)  If Size is not specified then a default value is determined
90
 *        based upon the number of inputs and outputs.
91
 *    BitsPerSample (required) Only 8, 16, 24, and 32 accepted,
92
 * The remaining keys are ignored.
93
 */
94
static int
95
zbuildsampledfunction(i_ctx_t *i_ctx_p)
96
0
{
97
0
    os_ptr op = osp;
98
0
    const ref * pdict = op;
99
0
    ref * pfunc;
100
0
    int code = 0;
101
0
    gs_function_t *pfn;
102
0
    gs_function_Sd_params_t params = {0};
103
104
0
    check_op(1);
105
0
    check_type(*pdict, t_dictionary);
106
    /*
107
     * Check procedure to be sampled.
108
     */
109
0
    if (dict_find_string(pdict, "Function", &pfunc) <= 0)
110
0
        return_error(gs_error_rangecheck);
111
0
    check_proc(*pfunc);
112
    /*
113
     * Set up the hyper cube function data structure.
114
     */
115
0
    code = cube_build_func0(pdict, &params, imemory);
116
0
    if (code < 0)
117
0
        return code;
118
    /*
119
     * This is temporary.  We will call gs_function_Sd_init again after
120
     * we have collected the cube data.  We are doing it now because we need
121
     * a function structure created (along with its GC enumeration stuff)
122
     * that we can use while collecting the cube data.  We will call
123
     * the routine again after the cube data is collected to correctly
124
     * initialize the function.
125
     */
126
0
    code = gs_function_Sd_init(&pfn, &params, imemory);
127
0
    if (code < 0)
128
0
        return code;
129
    /*
130
     * Now setup to collect the sample data.
131
     */
132
0
    return sampled_data_setup(i_ctx_p, pfn, pfunc, sampled_data_finish, imemory);
133
0
}
134
135
/* ------- Internal procedures ------- */
136
137
171k
#define bits2bytes(x) ((x) >> 3)  /* Convert bit count to byte count */
138
139
/*
140
 * This routine will verify that the requested data hypercube parameters will require
141
 * a data storage size less than or equal to the MAX_DATA_SIZE.
142
 */
143
static bool
144
valid_cube_size(int num_inputs, int num_outputs, int sample_size, const int Size[])
145
245
{
146
245
    int i, total_size = num_outputs * sample_size;
147
148
490
    for (i = 0; i < num_inputs; i++) {
149
245
        if (Size[i] <= 0 || Size[i] > MAX_DATA_SIZE / total_size)
150
0
            return false;
151
245
        total_size *= Size[i];
152
245
    }
153
245
    return true;
154
245
}
155
156
/*
157
 * This routine is used to determine a default value for the sampled data size.
158
 * As a default, we will build a hyper cube with each side having the same
159
 * size.  The space requirements for a hypercube grow exponentially with the
160
 * number of dimensions.  Thus we must use fewer points if our functions has
161
 * many inputs.  The values returned were chosen simply to given a reasonable
162
 * tradeoff between keeping storage requirements low but still having enough
163
 * points per side to minimize loss of information.
164
 *
165
 * We do check to see if the data will fit using our initial guess.  If not
166
 * then we decrement the size of each edge until it fits.  We will return a
167
 * gs_error_rangecheck error if the cube can not fit into the maximum  size.
168
 * On exit the Size array contains the cube size (if a valid size was found).
169
 */
170
static int
171
determine_sampled_data_size(int num_inputs, int num_outputs,
172
                                int sample_size, int Size[])
173
245
{
174
245
    static const int size_list[] = {512, 50, 20, 10, 7, 5, 4, 3};
175
245
    int i, size;
176
177
    /* Start with initial guess at cube size */
178
245
    if (num_inputs > 0 && num_inputs <= 8)
179
245
        size = size_list[num_inputs - 1];
180
0
    else
181
0
        size = 2;
182
    /*
183
     * Verify that the cube will fit into MAX_DATA_SIZE.  If not then
184
     * decrement the cube size until it will fit.
185
     */
186
245
    while (true) {
187
        /* Fill Size array with value. */
188
490
        for (i = 0; i < num_inputs; i++)
189
245
            Size[i] = size;
190
191
        /* If we have reached the minimum size (2), don't bother checking if its 'valid'
192
         * as there is nothing we cna do now if it isn't.
193
         */
194
245
        if (size > 2) {
195
245
            if (valid_cube_size(num_inputs, num_outputs, sample_size, Size))
196
245
                return 0;    /* We have a valid size */
197
0
            size--;
198
0
        } else {
199
0
            return 0;
200
0
        }
201
245
    }
202
245
}
203
204
/*
205
 * Allocate the enumerator used while collecting sampled data.  This enumerator
206
 * is used to hold the various state data required while sampling.
207
 */
208
static gs_sampled_data_enum *
209
gs_sampled_data_enum_alloc(gs_memory_t * mem, client_name_t cname)
210
245
{
211
245
    return gs_alloc_struct(mem, gs_sampled_data_enum,
212
245
                                &st_gs_sampled_data_enum, cname);
213
245
}
214
215
/*
216
 * This routine will determine the location of a block of data
217
 * in the hyper cube.  Basically this does an index calculation
218
 * for an n dimensional cube.
219
 */
220
static byte *
221
cube_ptr_from_index(gs_function_Sd_params_t * params, int indexes[])
222
85.5k
{
223
85.5k
    int i, sum = indexes[params->m - 1];
224
225
85.5k
    for (i = params->m - 2; i >= 0; i--) {
226
0
        sum *= params->Size[i];
227
0
        sum += indexes[i];
228
0
    }
229
85.5k
    return (byte *)(params->DataSource.data.str.data) +
230
85.5k
        sum * params->n * bits2bytes(params->BitsPerSample);
231
85.5k
}
232
233
/*
234
 * This routine will increment the index values for the hypercube.  This
235
 * is used for collecting the data.  If we have incremented the
236
 * last index beyond its last value then we return a true, else false;
237
 */
238
static bool
239
increment_cube_indexes(gs_function_Sd_params_t * params, int indexes[])
240
85.5k
{
241
85.5k
    int i = 0;
242
243
85.5k
    while (true) {
244
        /*
245
         * Increment an index value for an edge and test if we have
246
         * gone past the final value for the edge.
247
         */
248
85.5k
        indexes[i]++;
249
85.5k
        if (indexes[i] < params->Size[i])
250
            /*
251
             * We have not reached the end of the edge.  Exit but
252
             * indicate that we are not done with the hypercube.
253
             */
254
85.3k
            return false;
255
        /*
256
         * We have reached the end of one edge of the hypercube and we
257
         * need to increment the next index.
258
         */
259
167
        indexes[i] = 0;
260
167
        i++;
261
167
        if (i == params->m)
262
            /*
263
             * We have finished the last edge of the hyper cube.
264
             * We are done.
265
             */
266
167
            return true;
267
167
    }
268
85.5k
}
269
270
/*
271
 * Fill in the data for a function type 0 parameter object to be used while
272
 * we collect the data for the data cube.  At the end of the process, we
273
 * will create a function type 0 object to be used to calculate values
274
 * as a replacement for the original function.
275
 */
276
static int
277
cube_build_func0(const ref * pdict, gs_function_Sd_params_t * params,
278
                                                        gs_memory_t *mem)
279
0
{
280
0
    byte * bytes = 0;
281
0
    int code, i;
282
0
    int total_size;
283
284
0
    if ((code = dict_int_param(pdict, "Order", 1, 3, 1, &params->Order)) < 0 ||
285
0
        (code = dict_int_param(pdict, "BitsPerSample", 1, 32, 0,
286
0
                               &params->BitsPerSample)) < 0 ||
287
0
        ((code = params->m =
288
0
            fn_build_float_array(pdict, "Domain", false, true,
289
0
                                        &params->Domain, mem)) < 0 ) ||
290
0
        ((code = params->n =
291
0
            fn_build_float_array(pdict, "Range", false, true,
292
0
                                        &params->Range, mem)) < 0)
293
0
        ) {
294
0
        goto fail;
295
0
    }
296
    /*
297
     * The previous logic set the size of m and n to the size of the Domain
298
     * and Range arrays.  This is twice the actual size.  Correct this and
299
     * check for valid values.
300
     */
301
0
    params->m >>= 1;
302
0
    params->n >>= 1;
303
0
    if (params->m == 0 || params->n == 0 ||
304
0
        params->m > MAX_NUM_INPUTS || params->n > MAX_NUM_OUTPUTS) {
305
0
        code = gs_note_error(gs_error_rangecheck);
306
0
        goto fail;
307
0
    }
308
    /*
309
     * The Size array may or not be specified.  If it is not specified then
310
     * we need to determine a set of default values for the Size array.
311
     */
312
0
    {
313
0
        int *ptr = (int *)
314
0
            gs_alloc_byte_array(mem, params->m, sizeof(int), "Size");
315
316
0
        if (ptr == NULL) {
317
0
            code = gs_note_error(gs_error_VMerror);
318
0
            goto fail;
319
0
        }
320
0
        params->Size = ptr;
321
0
        code = dict_ints_param(mem, pdict, "Size", params->m, ptr);
322
0
        if (code < 0)
323
0
            goto fail;
324
0
        if (code == 0) {
325
            /*
326
             * The Size array has not been specified.  Determine a default
327
             * set of values.
328
             */
329
0
            code = determine_sampled_data_size(params->m, params->n,
330
0
                                params->BitsPerSample, (int *)params->Size);
331
0
            if (code < 0)
332
0
                goto fail;
333
0
        }
334
0
        else {     /* Size array specified - verify valid */
335
0
            if (code != params->m || !valid_cube_size(params->m, params->n,
336
0
                params->BitsPerSample, params->Size)) {
337
0
                    code = gs_note_error(gs_error_rangecheck);
338
0
                    goto fail;
339
0
            }
340
0
        }
341
0
    }
342
    /*
343
     * Determine space required for the sample data storage.
344
     */
345
0
    total_size = params->n * bits2bytes(params->BitsPerSample);
346
0
    for (i = 0; i < params->m; i++)
347
0
        total_size *= params->Size[i];
348
    /*
349
     * Allocate space for the data cube itself.
350
     */
351
0
    bytes = gs_alloc_byte_array(mem, total_size, 1, "cube_build_func0(bytes)");
352
0
    if (!bytes) {
353
0
        code = gs_note_error(gs_error_VMerror);
354
0
        goto fail;
355
0
    }
356
0
    data_source_init_bytes(&params->DataSource,
357
0
                                (const unsigned char *)bytes, total_size);
358
359
0
    return 0;
360
361
0
fail:
362
0
    gs_function_Sd_free_params(params, mem);
363
0
    return (code < 0 ? code : gs_note_error(gs_error_rangecheck));
364
0
}
365
366
/*
367
 * Layout of stuff pushed on estack while collecting the sampled data.
368
 * The data is saved there since it is safe from attack by the procedure
369
 * being sampled and is convient.
370
 *
371
 *      finishing procedure (or 0)
372
 *      procedure being sampled
373
 *      enumeration structure (as bytes)
374
 */
375
425
#define estack_storage 3
376
334
#define esp_finish_proc (*real_opproc(esp - 2))
377
55.8k
#define sample_proc esp[-1]
378
141k
#define senum r_ptr(esp, gs_sampled_data_enum)
379
/*
380
 * Sone invalid tint transform functions pop more items off of the stack
381
 * then they are supposed to use.  This is a violation of the PLRM however
382
 * this is done by Adobe and we have to handle the situation.  This is
383
 * a kludge but we set aside some unused stack space below the input
384
 * variables.  The tint transform can trash this without causing any
385
 * real problems.
386
 */
387
250k
#define O_STACK_PAD 3
388
389
/*
390
 * Set up to collect the data for the sampled function.  This is used for
391
 * those alternate tint transforms that cannot be converted into a
392
 * type 4 function.
393
 */
394
static int
395
sampled_data_setup(i_ctx_t *i_ctx_p, gs_function_t *pfn,
396
        const ref * pproc, int (*finish_proc)(i_ctx_t *), gs_memory_t * mem)
397
245
{
398
245
    os_ptr op = osp;
399
245
    gs_sampled_data_enum *penum;
400
245
    int i;
401
245
    gs_function_Sd_params_t * params = (gs_function_Sd_params_t *)&pfn->params;
402
403
245
    check_estack(estack_storage + 1);   /* Verify space on estack */
404
245
    check_ostack(params->m + O_STACK_PAD); /* and the operand stack */
405
245
    check_ostack(params->n + O_STACK_PAD);
406
407
    /*
408
     * Allocate space for the enumerator data structure.
409
     */
410
245
    penum = gs_sampled_data_enum_alloc(imemory, "zbuildsampledfuntion(params)");
411
245
    if (penum == NULL)
412
0
        return_error(gs_error_VMerror);
413
414
    /* Initialize data in the enumeration structure */
415
416
245
    penum->pfn = pfn;
417
490
    for(i=0; i< params->m; i++)
418
245
        penum->indexes[i] = 0;
419
    /*
420
     * Save stack depth for checking the correct number of values on stack
421
     * after the function, which is being sampled, is called.
422
     */
423
245
    penum->o_stack_depth = ref_stack_count(&o_stack);
424
    /*
425
     * Note:  As previously mentioned, we are putting some spare (unused) stack
426
     * space under the input values in case the function unbalances the stack.
427
     * It is possible for the function to pop or change values on the stack
428
     * outside of the input values.  (This has been found to happen with some
429
     * proc sets from Adobe.)
430
     */
431
245
    push(O_STACK_PAD);
432
980
    for (i = 0; i < O_STACK_PAD; i++)    /* Set space = null */
433
735
        make_null(op - i);
434
435
    /* Push everything on the estack */
436
437
245
    esp += estack_storage;
438
245
    make_op_estack(esp - 2, finish_proc); /* Finish proc onto estack */
439
245
    sample_proc = *pproc;      /* Save function to be sampled */
440
245
    make_istruct(esp, 0, penum);    /* Color cube enumeration structure */
441
245
    push_op_estack(sampled_data_sample);  /* Start sampling data */
442
245
    return o_push_estack;
443
245
}
444
445
/*
446
 * Set up to collect the next sampled data value.
447
 */
448
static int
449
sampled_data_sample(i_ctx_t *i_ctx_p)
450
55.5k
{
451
55.5k
    os_ptr op = osp;
452
55.5k
    gs_sampled_data_enum *penum = senum;
453
55.5k
    ref proc;
454
55.5k
    gs_function_Sd_params_t * params =
455
55.5k
                        (gs_function_Sd_params_t *)&penum->pfn->params;
456
55.5k
    int num_inputs = params->m;
457
55.5k
    int i;
458
459
    /* Put set of input values onto the stack. */
460
55.5k
    push(num_inputs);
461
111k
    for (i = 0; i < num_inputs; i++) {
462
55.5k
        double dmin = params->Domain[2 * i];
463
55.5k
        double dmax = params->Domain[2 * i + 1];
464
465
55.5k
        make_real(op - num_inputs + i + 1, (float) (
466
55.5k
            penum->indexes[i] * (dmax - dmin)/(params->Size[i] - 1) + dmin));
467
55.5k
    }
468
469
55.5k
    proc = sample_proc;         /* Get procedure from storage */
470
55.5k
    push_op_estack(sampled_data_continue);  /* Put 'save' routine on estack, after sample proc */
471
55.5k
    *++esp = proc;          /* Put procedure to be executed */
472
55.5k
    return o_push_estack;
473
55.5k
}
474
475
/*
476
 * Continuation procedure for processing sampled values.
477
 */
478
static int
479
sampled_data_continue(i_ctx_t *i_ctx_p)
480
85.5k
{
481
85.5k
    os_ptr op = osp;
482
85.5k
    gs_sampled_data_enum *penum = senum;
483
85.5k
    gs_function_Sd_params_t * params =
484
85.5k
            (gs_function_Sd_params_t *)&penum->pfn->params;
485
85.5k
    int i, j, num_out = params->n;
486
85.5k
    int code = 0;
487
85.5k
    byte * data_ptr;
488
85.5k
    double sampled_data_value_max = (double)((1 << params->BitsPerSample) - 1);
489
85.5k
    int bps = bits2bytes(params->BitsPerSample), stack_depth_adjust = 0;
490
491
    /*
492
     * Check to make sure that the procedure produced the correct number of
493
     * values.  If not, move the stack back to where it belongs and abort.
494
     * There are two forms of "stackunderflow" one is that there are genuinely
495
     * too few entries on the stack, the other is that there are too few entries
496
     * on this stack block. To establish the difference, we need to return the
497
     * stackunderflow error, without meddling with the exec stack, so gs_call_interp()
498
     * can try popping a stack block, and letting us retry.
499
     * Hence we check overall stack depth, *and* do check_op().
500
     */
501
85.5k
    if (num_out + O_STACK_PAD + penum->o_stack_depth != ref_stack_count(&o_stack)) {
502
81.9k
        stack_depth_adjust = ref_stack_count(&o_stack) - penum->o_stack_depth;
503
504
81.9k
        if (stack_depth_adjust < 0) {
505
            /*
506
             * If we get to here then there were major problems.  The function
507
             * removed too many items off of the stack.  We had placed extra
508
             * (unused) stack stack space to allow for this but the function
509
             * exceeded even that.  Data on the stack may have been lost.
510
             * The only thing that we can do is move the stack pointer back and
511
             * hope.
512
             */
513
20
            push(-stack_depth_adjust);
514
20
            return_error(gs_error_undefinedresult);
515
20
        }
516
81.9k
    }
517
85.5k
    if ( op < osbot + ((num_out) - 1) ) {
518
3
        return_error(gs_error_stackunderflow);
519
3
    }
520
    /* Save data from the given function */
521
85.5k
    data_ptr = cube_ptr_from_index(params, penum->indexes);
522
427k
    for (i=0; i < num_out; i++) {
523
342k
        ulong cv;
524
342k
        double value;
525
342k
        double rmin = params->Range[2 * i];
526
342k
        double rmax = params->Range[2 * i + 1];
527
528
342k
        code = real_param(op + i - num_out + 1, &value);
529
342k
        if (code < 0) {
530
13
            esp -= estack_storage;
531
13
            return code;
532
13
        }
533
342k
        if (value < rmin)
534
0
            value = rmin;
535
342k
        else if (value > rmax)
536
1.98k
            value = rmax;
537
342k
        value = (value - rmin) / (rmax - rmin);   /* Convert to 0 to 1.0 */
538
342k
        cv = (int) (value * sampled_data_value_max + 0.5);
539
1.02M
        for (j = 0; j < bps; j++)
540
684k
            data_ptr[bps * i + j] = (byte)(cv >> ((bps - 1 - j) * 8)); /* MSB first */
541
342k
    }
542
543
85.5k
    pop(num_out); /* Move op to base of result values */
544
545
    /* From here on, we have to use ref_stack_pop() rather than pop()
546
       so that it handles stack extension blocks properly, before calling
547
       sampled_data_sample() which also uses the op stack.
548
     */
549
    /* Check if we are done collecting data. */
550
85.5k
    if (increment_cube_indexes(params, penum->indexes)) {
551
167
        int to_pop;
552
167
        if (stack_depth_adjust == 0)
553
7
            if (ref_stack_count(&o_stack) >= O_STACK_PAD)
554
7
                to_pop = O_STACK_PAD;      /* Remove spare stack space */
555
0
            else
556
0
                to_pop = ref_stack_count(&o_stack);
557
160
        else
558
160
            to_pop = stack_depth_adjust - num_out;
559
560
167
        if (to_pop < 0)
561
0
            return_error(gs_error_stackunderflow);
562
563
167
        ref_stack_pop(&o_stack, to_pop);
564
565
        /* Execute the closing procedure, if given */
566
167
        code = 0;
567
167
        if (esp_finish_proc != 0)
568
167
            code = esp_finish_proc(i_ctx_p);
569
570
167
        return code;
571
85.3k
    } else {
572
85.3k
        if (stack_depth_adjust) {
573
81.8k
            stack_depth_adjust -= num_out;
574
81.8k
            if ((O_STACK_PAD - stack_depth_adjust) < 0) {
575
81.8k
                stack_depth_adjust = -(O_STACK_PAD - stack_depth_adjust);
576
81.8k
                check_op(stack_depth_adjust);
577
51.7k
                ref_stack_pop(&o_stack, stack_depth_adjust);
578
51.7k
            }
579
0
            else {
580
0
                check_ostack(O_STACK_PAD - stack_depth_adjust);
581
0
                ref_stack_push(&o_stack, O_STACK_PAD - stack_depth_adjust);
582
0
                for (i=0;i<O_STACK_PAD - stack_depth_adjust;i++)
583
0
                    make_null(op - i);
584
0
            }
585
81.8k
        }
586
85.3k
    }
587
588
    /* Now get the data for the next location */
589
590
55.3k
    return sampled_data_sample(i_ctx_p);
591
85.5k
}
592
593
/*
594
 * We have collected all of the sample data.  Create a type 0 function stucture.
595
 */
596
static int
597
sampled_data_finish(i_ctx_t *i_ctx_p)
598
167
{
599
167
    os_ptr op = osp;
600
167
    gs_sampled_data_enum *penum = senum;
601
    /* Build a type 0 function using the given parameters */
602
167
    gs_function_Sd_params_t * params =
603
167
        (gs_function_Sd_params_t *)&penum->pfn->params;
604
167
    gs_function_t * pfn;
605
167
    ref cref;     /* closure */
606
167
    int code = gs_function_Sd_init(&pfn, params, imemory);
607
608
167
    check_op(1);
609
167
    if (code < 0) {
610
0
        esp -= estack_storage;
611
0
        return code;
612
0
    }
613
614
167
    code = ialloc_ref_array(&cref, a_executable | a_execute, 2,
615
167
                            "sampled_data_finish(cref)");
616
167
    if (code < 0) {
617
0
        esp -= estack_storage;
618
0
        return code;
619
0
    }
620
621
167
    make_istruct_new(cref.value.refs, a_executable | a_execute, pfn);
622
167
    make_oper_new(cref.value.refs + 1, 0, zexecfunction);
623
167
    ref_assign(op, &cref);
624
625
    /* See bug #707007, explicitly freed structures on the stacks need to be made NULL */
626
167
    make_null(esp);
627
167
    esp -= estack_storage;
628
167
    ifree_object(penum->pfn, "sampled_data_finish(pfn)");
629
167
    ifree_object(penum, "sampled_data_finish(enum)");
630
167
    return o_pop_estack;
631
167
}
632
633
int make_sampled_function(i_ctx_t * i_ctx_p, ref *arr, ref *pproc, gs_function_t **func)
634
245
{
635
245
    int code = 0, *ptr, i, total_size, num_components, CIESubst;
636
245
    byte * bytes = 0;
637
245
    float *fptr;
638
245
    gs_function_t *pfn = *func;
639
245
    gs_function_Sd_params_t params = {0};
640
245
    ref alternatespace, *palternatespace = &alternatespace;
641
245
    PS_colour_space_t *space, *altspace;
642
643
245
    code = get_space_object(i_ctx_p, arr, &space);
644
245
    if (code < 0)
645
0
        return code;
646
245
    if (!space->alternateproc)
647
0
        return gs_error_typecheck;
648
245
    code = space->alternateproc(i_ctx_p, arr, &palternatespace, &CIESubst);
649
245
    if (code < 0)
650
0
        return code;
651
245
    code = get_space_object(i_ctx_p, palternatespace, &altspace);
652
245
    if (code < 0)
653
0
        return code;
654
    /*
655
     * Set up the hyper cube function data structure.
656
     */
657
    /* The amount of memory required grows dramatitcally with the number of inputs when
658
     * Order is 3 (cubic interpolation). This is the same test as used in determine_sampled_data_size()
659
     * below to limit the number of samples in the cube. We use it here to switch to the
660
     * cheaper (memory usage) linear interpolation if there are a lot of input
661
     * components, in the hope of being able to continue.
662
     */
663
245
    if (params.m <= 8)
664
245
        params.Order = 3;
665
0
    else
666
0
        params.Order = 1;
667
245
    params.BitsPerSample = 16;
668
669
245
    code = space->numcomponents(i_ctx_p, arr, &num_components);
670
245
    if (code < 0)
671
0
        return code;
672
245
    fptr = (float *)gs_alloc_byte_array(imemory, num_components * 2, sizeof(float), "make_sampled_function(Domain)");
673
245
    if (!fptr)
674
0
        return gs_error_VMerror;
675
245
    code = space->domain(i_ctx_p, arr, fptr);
676
245
    if (code < 0) {
677
0
        gs_free_const_object(imemory, fptr, "make_sampled_function(Domain)");
678
0
        return code;
679
0
    }
680
245
    params.Domain = fptr;
681
245
    params.m = num_components;
682
683
245
    if (params.m > MAX_NUM_INPUTS)
684
0
        return_error(gs_error_rangecheck);
685
686
245
    code = altspace->numcomponents(i_ctx_p, palternatespace, &num_components);
687
245
    if (code < 0) {
688
0
        gs_free_const_object(imemory, params.Domain, "make_type4_function(Domain)");
689
0
        return code;
690
0
    }
691
245
    fptr = (float *)gs_alloc_byte_array(imemory, num_components * 2, sizeof(float), "make_sampled_function(Range)");
692
245
    if (!fptr) {
693
0
        gs_free_const_object(imemory, params.Domain, "make_sampled_function(Domain)");
694
0
        return gs_error_VMerror;
695
0
    }
696
245
    code = altspace->range(i_ctx_p, palternatespace, fptr);
697
245
    if (code < 0) {
698
0
        gs_free_const_object(imemory, params.Domain, "make_sampled_function(Domain)");
699
0
        gs_free_const_object(imemory, fptr, "make_sampled_function(Range)");
700
0
        return code;
701
0
    }
702
245
    params.Range = fptr;
703
245
    params.n = num_components;
704
705
    /*
706
     * The Size array may or not be specified.  If it is not specified then
707
     * we need to determine a set of default values for the Size array.
708
     */
709
245
    ptr = (int *)gs_alloc_byte_array(imemory, params.m, sizeof(int), "Size");
710
245
    if (ptr == NULL) {
711
0
        code = gs_note_error(gs_error_VMerror);
712
0
        goto fail;
713
0
    }
714
245
    params.Size = ptr;
715
    /*
716
     * Determine a default
717
     * set of values.
718
     */
719
245
    code = determine_sampled_data_size(params.m, params.n,
720
245
                        params.BitsPerSample, (int *)params.Size);
721
245
    if (code < 0)
722
0
        goto fail;
723
    /*
724
     * Determine space required for the sample data storage.
725
     */
726
245
    total_size = params.n * bits2bytes(params.BitsPerSample);
727
490
    for (i = 0; i < params.m; i++)
728
245
        total_size *= params.Size[i];
729
    /*
730
     * Allocate space for the data cube itself.
731
     */
732
245
    bytes = gs_alloc_byte_array(imemory, total_size, 1, "cube_build_func0(bytes)");
733
245
    if (!bytes) {
734
0
        code = gs_note_error(gs_error_VMerror);
735
0
        goto fail;
736
0
    }
737
245
    data_source_init_bytes(&params.DataSource,
738
245
                                (const unsigned char *)bytes, total_size);
739
740
    /*
741
     * This is temporary.  We will call gs_function_Sd_init again after
742
     * we have collected the cube data.  We are doing it now because we need
743
     * a function structure created (along with its GC enumeration stuff)
744
     * that we can use while collecting the cube data.  We will call
745
     * the routine again after the cube data is collected to correctly
746
     * initialize the function.
747
     */
748
245
    code = gs_function_Sd_init(&pfn, &params, imemory);
749
245
    if (code < 0)
750
0
        return code;
751
    /*
752
     * Now setup to collect the sample data.
753
     */
754
245
    return sampled_data_setup(i_ctx_p, pfn, pproc, sampled_data_finish, imemory);
755
756
0
fail:
757
0
    gs_function_Sd_free_params(&params, imemory);
758
0
    return code;
759
245
}
760
761
/* ------ Initialization procedure ------ */
762
763
const op_def zfsample_op_defs[] =
764
{
765
    op_def_begin_level2(),
766
    {"1.buildsampledfunction", zbuildsampledfunction},
767
    op_def_end(0)
768
};