Coverage Report

Created: 2025-04-22 06:20

/src/libspectre/ghostscript/base/gsfunc4.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2020 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
/* Implementation of FunctionType 4 (PostScript Calculator) Functions */
18
#include "math_.h"
19
#include "memory_.h"
20
#include "gx.h"
21
#include "gserrors.h"
22
#include "gsdsrc.h"
23
#include "gsfunc4.h"
24
#include "gxfarith.h"
25
#include "gxfunc.h"
26
#include "stream.h"
27
#include "strimpl.h"
28
#include "sfilter.h"    /* for SubFileDecode */
29
#include "spprint.h"
30
#include "stream.h"
31
32
typedef struct gs_function_PtCr_s {
33
    gs_function_head_t head;
34
    gs_function_PtCr_params_t params;
35
    /* Define a bogus DataSource for get_function_info. */
36
    gs_data_source_t data_source;
37
} gs_function_PtCr_t;
38
39
/* GC descriptor */
40
private_st_function_PtCr();
41
42
/* Define the maximum stack depth. */
43
0
#define MAX_VSTACK 256    /* Max 100 is enough per PDF spec, but we use this
44
                                 * for DeviceN handling. Must be at least as large
45
                                 * as the number of components
46
                                 */
47
48
/* Define the structure of values on the stack. */
49
typedef enum {
50
    CVT_NONE = 0, /* empty stack slot */
51
    CVT_BOOL,
52
    CVT_INT,
53
    CVT_FLOAT
54
} calc_value_type_t;
55
typedef struct calc_value_s {
56
    calc_value_type_t type;
57
    union {
58
        int i;      /* also used for Boolean */
59
        float f;
60
    } value;
61
} calc_value_t;
62
63
/* Store a float. */
64
static inline void
65
store_float(calc_value_t *vsp, double f)
66
0
{
67
0
    vsp->value.f = f;
68
0
    vsp->type = CVT_FLOAT;
69
0
}
70
71
/*
72
 * Define extended opcodes with typed operands.  We use the original
73
 * opcodes for the floating-point case.
74
 */
75
typedef enum {
76
77
        /* Typed variants */
78
79
    PtCr_abs_int = PtCr_NUM_OPCODES,
80
    PtCr_add_int,
81
    PtCr_mul_int,
82
    PtCr_neg_int,
83
    PtCr_not_bool,    /* default is int */
84
    PtCr_sub_int,
85
    PtCr_eq_int,
86
    PtCr_ge_int,
87
    PtCr_gt_int,
88
    PtCr_le_int,
89
    PtCr_lt_int,
90
    PtCr_ne_int,
91
92
        /* Coerce and re-dispatch */
93
94
    PtCr_int_to_float,
95
    PtCr_2nd_int_to_float,
96
    PtCr_int2_to_float,
97
98
        /* Miscellaneous */
99
100
    PtCr_no_op,
101
    PtCr_typecheck
102
103
} gs_PtCr_typed_opcode_t;
104
105
/* Evaluate a PostScript Calculator function. */
106
static int
107
fn_PtCr_evaluate(const gs_function_t *pfn_common, const float *in, float *out)
108
0
{
109
0
    const gs_function_PtCr_t *pfn = (const gs_function_PtCr_t *)pfn_common;
110
0
    calc_value_t vstack_buf[2 + MAX_VSTACK + 1];
111
0
    calc_value_t *vstack = &vstack_buf[1];
112
0
    calc_value_t *vsp = vstack + pfn->params.m;
113
0
    const byte *p = pfn->params.ops.data;
114
0
    int repeat_count[MAX_PSC_FUNCTION_NESTING];
115
0
    int repeat_proc_size[MAX_PSC_FUNCTION_NESTING];
116
0
    int repeat_nesting_level = -1;
117
0
    int i;
118
119
    /*
120
     * Define the table for mapping explicit opcodes to typed opcodes.
121
     * We index this table with the opcode and the types of the top 2
122
     * values on the stack.
123
     */
124
0
    static const struct op_defn_s {
125
0
        byte opcode[16];  /* 4 * type[-1] + type[0] */
126
0
    } op_defn_table[] = {
127
        /* Keep this consistent with opcodes in gsfunc4.h! */
128
129
0
#define O4(op) op,op,op,op
130
0
#define E PtCr_typecheck
131
0
#define E4 O4(E)
132
0
#define N PtCr_no_op
133
        /* 0-operand operators */
134
0
#define OP_NONE(op)\
135
0
  {{O4(op), O4(op), O4(op), O4(op)}}
136
        /* 1-operand operators */
137
0
#define OP1(b, i, f)\
138
0
  {{E,b,i,f, E,b,i,f, E,b,i,f, E,b,i,f}}
139
0
#define OP_NUM1(i, f)\
140
0
  OP1(E, i, f)
141
0
#define OP_MATH1(f)\
142
0
  OP1(E, PtCr_int_to_float, f)
143
0
#define OP_ANY1(op)\
144
0
  OP1(op, op, op)
145
        /* 2-operand operators */
146
0
#define OP_NUM2(i, f)\
147
0
  {{E4, E4, E,E,i,PtCr_2nd_int_to_float, E,E,PtCr_int_to_float,f}}
148
0
#define OP_INT_BOOL2(i)\
149
0
  {{E4, E,i,i,E, E,i,i,E, E4}}
150
0
#define OP_MATH2(f)\
151
0
  {{E4, E4, E,E,PtCr_int2_to_float,PtCr_2nd_int_to_float,\
152
0
    E,E,PtCr_int_to_float,f}}
153
0
#define OP_INT2(i)\
154
0
  {{E4, E4, E,E,i,E, E4}}
155
0
#define OP_REL2(i, f)\
156
0
  {{E4, E,i,E,E, E,E,i,PtCr_2nd_int_to_float, E,E,PtCr_int_to_float,f}}
157
0
#define OP_ANY2(op)\
158
0
  {{E4, E,op,op,op, E,op,op,op, E,op,op,op}}
159
160
    /* Arithmetic operators */
161
162
0
        OP_NUM1(PtCr_abs_int, PtCr_abs), /* abs */
163
0
        OP_NUM2(PtCr_add_int, PtCr_add), /* add */
164
0
        OP_INT_BOOL2(PtCr_and),  /* and */
165
0
        OP_MATH2(PtCr_atan),  /* atan */
166
0
        OP_INT2(PtCr_bitshift),  /* bitshift */
167
0
        OP_NUM1(N, PtCr_ceiling),  /* ceiling */
168
0
        OP_MATH1(PtCr_cos), /* cos */
169
0
        OP_NUM1(N, PtCr_cvi),  /* cvi */
170
0
        OP_NUM1(PtCr_int_to_float, N), /* cvr */
171
0
        OP_MATH2(PtCr_div), /* div */
172
0
        OP_MATH2(PtCr_exp), /* exp */
173
0
        OP_NUM1(N, PtCr_floor),  /* floor */
174
0
        OP_INT2(PtCr_idiv),  /* idiv */
175
0
        OP_MATH1(PtCr_ln),  /* ln */
176
0
        OP_MATH1(PtCr_log), /* log */
177
0
        OP_INT2(PtCr_mod), /* mod */
178
0
        OP_NUM2(PtCr_mul_int, PtCr_mul), /* mul */
179
0
        OP_NUM1(PtCr_neg_int, PtCr_neg), /* neg */
180
0
        OP1(PtCr_not, PtCr_not, E),  /* not */
181
0
        OP_INT_BOOL2(PtCr_or),  /* or */
182
0
        OP_NUM1(N, PtCr_round),  /* round */
183
0
        OP_MATH1(PtCr_sin), /* sin */
184
0
        OP_MATH1(PtCr_sqrt),  /* sqrt */
185
0
        OP_NUM2(PtCr_sub_int, PtCr_sub), /* sub */
186
0
        OP_NUM1(N, PtCr_truncate), /* truncate */
187
0
        OP_INT_BOOL2(PtCr_xor),  /* xor */
188
189
    /* Comparison operators */
190
191
0
        OP_REL2(PtCr_eq_int, PtCr_eq), /* eq */
192
0
        OP_NUM2(PtCr_ge_int, PtCr_ge), /* ge */
193
0
        OP_NUM2(PtCr_gt_int, PtCr_gt), /* gt */
194
0
        OP_NUM2(PtCr_le_int, PtCr_le), /* le */
195
0
        OP_NUM2(PtCr_lt_int, PtCr_lt), /* lt */
196
0
        OP_REL2(PtCr_ne_int, PtCr_ne), /* ne */
197
198
    /* Stack operators */
199
200
0
        OP1(E, PtCr_copy, E),  /* copy */
201
0
        OP_ANY1(PtCr_dup), /* dup */
202
0
        OP_ANY2(PtCr_exch),  /* exch */
203
0
        OP1(E, PtCr_index, E), /* index */
204
0
        OP_ANY1(PtCr_pop), /* pop */
205
0
        OP_INT2(PtCr_roll),  /* roll */
206
207
    /* Constants */
208
209
0
        OP_NONE(PtCr_byte),    /* byte */
210
0
        OP_NONE(PtCr_int),   /* int */
211
0
        OP_NONE(PtCr_float),   /* float */
212
0
        OP_NONE(PtCr_true),    /* true */
213
0
        OP_NONE(PtCr_false),   /* false */
214
215
    /* Special */
216
217
0
        OP1(PtCr_if, E, E),    /* if */
218
0
        OP_NONE(PtCr_else),    /* else */
219
0
        OP_NONE(PtCr_return),    /* return */
220
0
        OP1(E, PtCr_repeat, E),    /* repeat */
221
0
        OP_NONE(PtCr_repeat_end) /* repeat_end */
222
0
    };
223
224
0
    memset(repeat_count, 0x00, MAX_PSC_FUNCTION_NESTING * sizeof(int));
225
0
    memset(repeat_proc_size, 0x00, MAX_PSC_FUNCTION_NESTING * sizeof(int));
226
227
0
    vstack[-1].type = CVT_NONE;  /* for type dispatch in empty stack case */
228
0
    vstack[0].type = CVT_NONE;  /* catch underflow */
229
0
    for (i = 0; i < pfn->params.m; ++i)
230
0
        store_float(&vstack[i + 1], in[i]);
231
232
0
    for (; ; ) {
233
0
        int code, n;
234
235
0
    sw:
236
0
        switch (op_defn_table[*p++].opcode[(vsp[-1].type << 2) + vsp->type]) {
237
238
            /* Miscellaneous */
239
240
0
        case PtCr_no_op:
241
0
            continue;
242
0
        case PtCr_typecheck:
243
0
            return_error(gs_error_typecheck);
244
245
            /* Coerce and re-dispatch */
246
247
0
        case PtCr_int_to_float:
248
0
            store_float(vsp, (double)vsp->value.i);
249
0
            --p; goto sw;
250
0
        case PtCr_int2_to_float:
251
0
            store_float(vsp, (double)vsp->value.i);
252
            /* fall through */
253
0
        case PtCr_2nd_int_to_float:
254
0
            store_float(vsp - 1, (double)vsp[-1].value.i);
255
0
            --p; goto sw;
256
257
            /* Arithmetic operators */
258
259
0
        case PtCr_abs_int:
260
0
            if (vsp->value.i < 0)
261
0
                goto neg_int;
262
0
            continue;
263
0
        case PtCr_abs:
264
0
            vsp->value.f = fabs(vsp->value.f);
265
0
            continue;
266
0
        case PtCr_add_int: {
267
0
            int int1 = vsp[-1].value.i, int2 = vsp->value.i;
268
269
0
            if ((int1 ^ int2) >= 0 && ((int1 + int2) ^ int1) < 0)
270
0
                store_float(vsp - 1, (double)int1 + int2);
271
0
            else
272
0
                vsp[-1].value.i = int1 + int2;
273
0
            --vsp; continue;
274
0
        }
275
0
        case PtCr_add:
276
0
            vsp[-1].value.f += vsp->value.f;
277
0
            --vsp; continue;
278
0
        case PtCr_and:
279
0
            vsp[-1].value.i &= vsp->value.i;
280
0
            --vsp; continue;
281
0
        case PtCr_atan: {
282
0
            double result;
283
284
0
            code = gs_atan2_degrees(vsp[-1].value.f, vsp->value.f,
285
0
                                    &result);
286
0
            if (code < 0)
287
0
                return code;
288
0
            vsp[-1].value.f = result;
289
0
            --vsp; continue;
290
0
        }
291
0
        case PtCr_bitshift:
292
0
#define MAX_SHIFT (ARCH_SIZEOF_INT * 8 - 1)
293
0
            if (vsp->value.i < -MAX_SHIFT || vsp->value.i > MAX_SHIFT)
294
0
                vsp[-1].value.i = 0;
295
0
#undef MAX_SHIFT
296
0
            else if ((n = vsp->value.i) < 0)
297
0
                vsp[-1].value.i = ((uint)(vsp[-1].value.i)) >> -n;
298
0
            else
299
0
                vsp[-1].value.i <<= n;
300
0
            --vsp; continue;
301
0
        case PtCr_ceiling:
302
0
            vsp->value.f = ceil(vsp->value.f);
303
0
            continue;
304
0
        case PtCr_cos:
305
0
            vsp->value.f = gs_cos_degrees(vsp->value.f);
306
0
            continue;
307
0
        case PtCr_cvi:
308
0
        {
309
           /* Strictly speaking assigning one element of union
310
            * to another, overlapping element of a different size is
311
            * undefined behavior, hence assign to an intermediate variable
312
            */
313
0
            int int1 = (int)(vsp->value.f);
314
0
            vsp->value.i = int1;
315
0
            vsp->type = CVT_INT;
316
0
            continue;
317
0
        }
318
0
        case PtCr_cvr:
319
0
            continue; /* prepare handled it */
320
0
        case PtCr_div:
321
0
            if (vsp->value.f == 0)
322
0
                return_error(gs_error_undefinedresult);
323
0
            vsp[-1].value.f /= vsp->value.f;
324
0
            --vsp; continue;
325
0
        case PtCr_exp:
326
0
            vsp[-1].value.f = pow(vsp[-1].value.f, vsp->value.f);
327
0
            --vsp; continue;
328
0
        case PtCr_floor:
329
0
            vsp->value.f = floor(vsp->value.f);
330
0
            continue;
331
0
        case PtCr_idiv:
332
0
            if (vsp->value.i == 0)
333
0
                return_error(gs_error_undefinedresult);
334
0
            if ((vsp[-1].value.i /= vsp->value.i) == min_int &&
335
0
                vsp->value.i == -1)  /* anomalous boundary case, fail */
336
0
                return_error(gs_error_rangecheck);
337
0
            --vsp; continue;
338
0
        case PtCr_ln:
339
0
            vsp->value.f = log(vsp->value.f);
340
0
            continue;
341
0
        case PtCr_log:
342
0
            vsp->value.f = log10(vsp->value.f);
343
0
            continue;
344
0
        case PtCr_mod:
345
0
            if (vsp->value.i == 0)
346
0
                return_error(gs_error_undefinedresult);
347
0
            vsp[-1].value.i %= vsp->value.i;
348
0
            --vsp; continue;
349
0
        case PtCr_mul_int: {
350
            /* We don't bother to optimize this. */
351
0
            double prod = (double)vsp[-1].value.i * vsp->value.i;
352
353
0
            if (prod < min_int || prod > max_int)
354
0
                store_float(vsp - 1, prod);
355
0
            else
356
0
                vsp[-1].value.i = (int)prod;
357
0
            --vsp; continue;
358
0
        }
359
0
        case PtCr_mul:
360
0
            vsp[-1].value.f *= vsp->value.f;
361
0
            --vsp; continue;
362
0
        case PtCr_neg_int:
363
0
        neg_int:
364
0
            if (vsp->value.i == min_int)
365
0
                store_float(vsp, (double)vsp->value.i); /* =self negated */
366
0
            else
367
0
                vsp->value.i = -vsp->value.i;
368
0
            continue;
369
0
        case PtCr_neg:
370
0
            vsp->value.f = -vsp->value.f;
371
0
            continue;
372
0
        case PtCr_not_bool:
373
0
            vsp->value.i = !vsp->value.i;
374
0
            continue;
375
0
        case PtCr_not:
376
0
            vsp->value.i = ~vsp->value.i;
377
0
            continue;
378
0
        case PtCr_or:
379
0
            vsp[-1].value.i |= vsp->value.i;
380
0
            --vsp; continue;
381
0
        case PtCr_round:
382
0
            vsp->value.f = floor(vsp->value.f + 0.5);
383
0
            continue;
384
0
        case PtCr_sin:
385
0
            vsp->value.f = gs_sin_degrees(vsp->value.f);
386
0
            continue;
387
0
        case PtCr_sqrt:
388
0
            vsp->value.f = sqrt(vsp->value.f);
389
0
            continue;
390
0
        case PtCr_sub_int: {
391
0
            int int1 = vsp[-1].value.i, int2 = vsp->value.i;
392
393
0
            if ((int1 ^ int2) < 0 && ((int1 - int2) ^ int1) >= 0)
394
0
                store_float(vsp - 1, (double)int1 - int2);
395
0
            else
396
0
                vsp[-1].value.i = int1 - int2;
397
0
            --vsp; continue;
398
0
        }
399
0
        case PtCr_sub:
400
0
            vsp[-1].value.f -= vsp->value.f;
401
0
            --vsp; continue;
402
0
        case PtCr_truncate:
403
0
            vsp->value.f = (vsp->value.f < 0 ? ceil(vsp->value.f) :
404
0
                            floor(vsp->value.f));
405
0
            continue;
406
0
        case PtCr_xor:
407
0
            vsp[-1].value.i ^= vsp->value.i;
408
0
            --vsp; continue;
409
410
            /* Boolean operators */
411
412
0
#define DO_REL(rel, m)\
413
0
  vsp[-1].value.i = vsp[-1].value.m rel vsp->value.m
414
415
0
        case PtCr_eq_int:
416
0
            DO_REL(==, i);
417
0
            goto rel;
418
0
        case PtCr_eq:
419
0
            DO_REL(==, f);
420
0
        rel:
421
0
            vsp[-1].type = CVT_BOOL;
422
0
            --vsp; continue;
423
0
        case PtCr_ge_int:
424
0
            DO_REL(>=, i);
425
0
            goto rel;
426
0
        case PtCr_ge:
427
0
            DO_REL(>=, f);
428
0
            goto rel;
429
0
        case PtCr_gt_int:
430
0
            DO_REL(>, i);
431
0
            goto rel;
432
0
        case PtCr_gt:
433
0
            DO_REL(>, f);
434
0
            goto rel;
435
0
        case PtCr_le_int:
436
0
            DO_REL(<=, i);
437
0
            goto rel;
438
0
        case PtCr_le:
439
0
            DO_REL(<=, f);
440
0
            goto rel;
441
0
        case PtCr_lt_int:
442
0
            DO_REL(<, i);
443
0
            goto rel;
444
0
        case PtCr_lt:
445
0
            DO_REL(<, f);
446
0
            goto rel;
447
0
        case PtCr_ne_int:
448
0
            DO_REL(!=, i);
449
0
            goto rel;
450
0
        case PtCr_ne:
451
0
            DO_REL(!=, f);
452
0
            goto rel;
453
454
0
#undef DO_REL
455
456
            /* Stack operators */
457
458
0
        case PtCr_copy:
459
0
            i = vsp->value.i;
460
0
            n = vsp - vstack;
461
0
            if (i < 0 || i >= n)
462
0
                return_error(gs_error_rangecheck);
463
0
            if (i > MAX_VSTACK - (n - 1))
464
0
                return_error(gs_error_limitcheck);
465
0
            memcpy(vsp, vsp - i, i * sizeof(*vsp));
466
0
            vsp += i - 1;
467
0
            continue;
468
0
        case PtCr_dup:
469
0
            vsp[1] = *vsp;
470
0
            goto push;
471
0
        case PtCr_exch:
472
0
            vstack[MAX_VSTACK] = *vsp;
473
0
            *vsp = vsp[-1];
474
0
            vsp[-1] = vstack[MAX_VSTACK];
475
0
            continue;
476
0
        case PtCr_index:
477
0
            i = vsp->value.i;
478
0
            if (i < 0 || i >= vsp - vstack - 1)
479
0
                return_error(gs_error_rangecheck);
480
0
            *vsp = vsp[-i - 1];
481
0
            continue;
482
0
        case PtCr_pop:
483
0
            --vsp;
484
0
            continue;
485
0
        case PtCr_roll:
486
0
            n = vsp[-1].value.i;
487
0
            i = vsp->value.i;
488
0
            if (n < 0 || n > vsp - vstack - 2)
489
0
                return_error(gs_error_rangecheck);
490
            /* We don't bother to do this efficiently. */
491
0
            for (; i > 0; i--) {
492
0
                memmove(vsp - n, vsp - (n + 1), n * sizeof(*vsp));
493
0
                vsp[-(n + 1)] = vsp[-1];
494
0
            }
495
0
            for (; i < 0; i++) {
496
0
                vsp[-1] = vsp[-(n + 1)];
497
0
                memmove(vsp - (n + 1), vsp - n, n * sizeof(*vsp));
498
0
            }
499
0
            vsp -= 2;
500
0
            continue;
501
502
            /* Constants */
503
504
0
        case PtCr_byte:
505
0
            vsp[1].value.i = *p++, vsp[1].type = CVT_INT;
506
0
            goto push;
507
0
        case PtCr_int /* native */:
508
0
            memcpy(&vsp[1].value.i, p, sizeof(int));
509
0
            vsp[1].type = CVT_INT;
510
0
            p += sizeof(int);
511
0
            goto push;
512
0
        case PtCr_float /* native */:
513
0
            memcpy(&vsp[1].value.f, p, sizeof(float));
514
0
            vsp[1].type = CVT_FLOAT;
515
0
            p += sizeof(float);
516
0
            goto push;
517
0
        case PtCr_true:
518
0
            vsp[1].value.i = true, vsp[1].type = CVT_BOOL;
519
0
            goto push;
520
0
        case PtCr_false:
521
0
            vsp[1].value.i = false, vsp[1].type = CVT_BOOL;
522
0
        push:
523
0
            if (vsp == &vstack[MAX_VSTACK])
524
0
                return_error(gs_error_limitcheck);
525
0
            ++vsp;
526
0
            continue;
527
528
            /* Special */
529
530
0
        case PtCr_if:
531
0
            if ((vsp--)->value.i) { /* value is true, execute body */
532
0
                p += 2;
533
0
                continue;
534
0
            }
535
            /* falls through */
536
0
        case PtCr_else:
537
0
            p += 2 + (p[0] << 8) + p[1];  /* skip the past body */
538
0
            continue;
539
0
        case PtCr_return:
540
0
            goto fin;
541
0
        case PtCr_repeat:
542
0
            repeat_nesting_level++;
543
0
            repeat_count[repeat_nesting_level] = vsp->value.i;
544
0
            repeat_proc_size[repeat_nesting_level] = 1 + (p[0] << 8) + p[1];  /* body size */
545
0
            --vsp;    /* pop the counter */
546
0
            p += 3 + (p[0] <<8) + p[1];       /* advance just past the repeat_end */
547
            /* falls through */
548
0
        case PtCr_repeat_end:
549
0
            if (repeat_nesting_level < 0)
550
0
                return_error(gs_error_rangecheck);
551
552
0
            if ((repeat_count[repeat_nesting_level])-- <= 0)
553
0
                repeat_nesting_level--;
554
0
            else
555
0
                p -= repeat_proc_size[repeat_nesting_level];
556
0
            continue;
557
0
        }
558
0
    }
559
0
 fin:
560
561
0
    if (vsp != vstack + pfn->params.n)
562
0
        return_error(gs_error_rangecheck);
563
0
    for (i = 0; i < pfn->params.n; ++i) {
564
0
        switch (vstack[i + 1].type) {
565
0
        case CVT_INT:
566
0
            out[i] = (float)vstack[i + 1].value.i;
567
0
            break;
568
0
        case CVT_FLOAT:
569
0
            out[i] = vstack[i + 1].value.f;
570
0
            break;
571
0
        default:
572
0
            return_error(gs_error_typecheck);
573
0
        }
574
0
    }
575
0
    return 0;
576
0
}
577
578
/* Test whether a PostScript Calculator function is monotonic. */
579
static int
580
fn_PtCr_is_monotonic(const gs_function_t * pfn_common,
581
                     const float *lower, const float *upper, uint *mask)
582
0
{
583
    /*
584
     * No reasonable way to tell.  Eventually we should check for
585
     * functions consisting of only stack-manipulating operations,
586
     * since these may be common for DeviceN color spaces and *are*
587
     * monotonic.
588
     */
589
0
    *mask = 0x49249249;
590
0
    return 0;
591
0
}
592
593
/* Write the function definition in symbolic form on a stream. */
594
static int
595
calc_put_ops(stream *s, const byte *ops, uint size)
596
0
{
597
0
    const byte *p;
598
599
0
    spputc(s, '{');
600
0
    for (p = ops; p < ops + size; )
601
0
        switch (*p++) {
602
0
        case PtCr_byte:
603
0
            pprintd1(s, "%d ", *p++);
604
0
            break;
605
0
        case PtCr_int: {
606
0
            int i;
607
608
0
            memcpy(&i, p, sizeof(int));
609
0
            pprintd1(s, "%d ", i);
610
0
            p += sizeof(int);
611
0
            break;
612
0
        }
613
0
        case PtCr_float: {
614
0
            float f;
615
616
0
            memcpy(&f, p, sizeof(float));
617
0
            pprintg1(s, "%g ", f);
618
0
            p += sizeof(float);
619
0
            break;
620
0
        }
621
0
        case PtCr_true:
622
0
            stream_puts(s, "true ");
623
0
            break;
624
0
        case PtCr_false:
625
0
            stream_puts(s, "false ");
626
0
            break;
627
0
        case PtCr_if: {
628
0
            int skip = (p[0] << 8) + p[1];
629
0
            int code;
630
631
0
            code = calc_put_ops(s, p += 2, skip);
632
0
            p += skip;
633
0
            if (code < 0)
634
0
                return code;
635
0
            if (code > 0) { /* else */
636
0
                skip = (p[-2] << 8) + p[-1];
637
0
                code = calc_put_ops(s, p, skip);
638
0
                p += skip;
639
0
                if (code < 0)
640
0
                    return code;
641
0
                stream_puts(s, " ifelse ");
642
0
            } else
643
0
                stream_puts(s, " if ");
644
0
            break;
645
0
        }
646
0
        case PtCr_else:
647
0
            if (p != ops + size - 2)
648
0
                return_error(gs_error_rangecheck);
649
0
            spputc(s, '}');
650
0
            return 1;
651
        /*case PtCr_return:*/ /* not possible */
652
0
        case PtCr_repeat:   /* We shouldn't encounter this, but just in case */
653
0
        case PtCr_repeat_end:
654
0
            return_error(gs_error_rangecheck);
655
0
        default: {    /* must be < PtCr_NUM_OPS */
656
0
                static const char *const op_names[] = {
657
                    /* Keep this consistent with opcodes in gsfunc4.h! */
658
0
                    "abs", "add", "and", "atan", "bitshift",
659
0
                    "ceiling", "cos", "cvi", "cvr", "div", "exp",
660
0
                    "floor", "idiv", "ln", "log", "mod", "mul",
661
0
                    "neg", "not", "or", "round", "sin", "sqrt", "sub",
662
0
                    "truncate", "xor",
663
0
                    "eq", "ge", "gt", "le", "lt", "ne",
664
0
                    "copy", "dup", "exch", "index", "pop", "roll"
665
0
                };
666
667
0
                pprints1(s, "%s ", op_names[p[-1]]);
668
0
            }
669
0
        }
670
0
    spputc(s, '}');
671
0
    return 0;
672
0
}
673
static int
674
calc_put(stream *s, const gs_function_PtCr_t *pfn)
675
0
{
676
0
    calc_put_ops(s, pfn->params.ops.data, pfn->params.ops.size - 1);
677
0
    return 0;
678
0
}
679
680
/* Access the symbolic definition as a DataSource. */
681
static int
682
calc_access(const gs_data_source_t *psrc, ulong start, uint length,
683
            byte *buf, const byte **ptr)
684
0
{
685
0
    const gs_function_PtCr_t *const pfn =
686
0
        (const gs_function_PtCr_t *)
687
0
          ((const char *)psrc - offset_of(gs_function_PtCr_t, data_source));
688
    /*
689
     * The caller wants a specific substring of the symbolic definition.
690
     * Generate the entire definition, using a SubFileDecode filter (in an
691
     * output pipeline!) to extract the substring.  This is very
692
     * inefficient, but this code is rarely used, and almost never actually
693
     * has to break up the definition into pieces to fit in the caller's
694
     * buffer.
695
     */
696
0
    stream_SFD_state st;
697
0
    stream ds, bs;
698
0
    byte dbuf[200];   /* arbitrary */
699
0
    const stream_template *const templat = &s_SFD_template;
700
701
    /* Set up the stream that writes into the buffer. */
702
0
    s_init(&bs, NULL);
703
0
    swrite_string(&bs, buf, length);
704
    /* Set up the SubFileDecode stream. */
705
0
    s_init(&ds, NULL);
706
0
    s_init_state((stream_state *)&st, templat, NULL);
707
0
    templat->set_defaults((stream_state *)&st);
708
0
    st.skip_count = start;
709
0
    s_init_filter(&ds, (stream_state *)&st, dbuf, sizeof(dbuf), &bs);
710
0
    calc_put(&ds, pfn);
711
0
    sclose(&ds);
712
0
    if (ptr)
713
0
        *ptr = buf;
714
0
    return 0;
715
0
}
716
717
/* Return PostScript Calculator function information. */
718
static void
719
fn_PtCr_get_info(const gs_function_t *pfn_common, gs_function_info_t *pfi)
720
0
{
721
0
    const gs_function_PtCr_t *const pfn =
722
0
        (const gs_function_PtCr_t *)pfn_common;
723
724
0
    gs_function_get_info_default(pfn_common, pfi);
725
0
    pfi->DataSource = &pfn->data_source;
726
0
    {
727
0
        stream s;
728
729
0
        s_init(&s, NULL);
730
0
        swrite_position_only(&s);
731
0
        calc_put(&s, pfn);
732
0
        pfi->data_size = stell(&s);
733
0
    }
734
0
}
735
736
/* Make a scaled copy of a PostScript Calculator function. */
737
static int
738
fn_PtCr_make_scaled(const gs_function_PtCr_t *pfn, gs_function_PtCr_t **ppsfn,
739
                    const gs_range_t *pranges, gs_memory_t *mem)
740
0
{
741
0
    gs_function_PtCr_t *psfn =
742
0
        gs_alloc_struct(mem, gs_function_PtCr_t, &st_function_PtCr,
743
0
                        "fn_PtCr_make_scaled");
744
    /* We are adding {<int> 1 roll <float> mul <float> add} for each output. */
745
0
    int n = pfn->params.n;
746
0
    uint opsize = pfn->params.ops.size + (9 + 2 * sizeof(float)) * n;
747
0
    byte *ops = gs_alloc_string(mem, opsize, "fn_PtCr_make_scaled(ops)");
748
0
    byte *p;
749
0
    int code, i;
750
751
0
    if (psfn == 0 || ops == 0) {
752
0
        gs_free_string(mem, ops, opsize, "fn_PtCr_make_scaled(ops)");
753
0
        gs_free_object(mem, psfn, "fn_PtCr_make_scaled");
754
0
        return_error(gs_error_VMerror);
755
0
    }
756
0
    psfn->params = pfn->params;
757
0
    psfn->params.ops.data = ops;
758
0
    psfn->params.ops.size = opsize;
759
0
    psfn->data_source = pfn->data_source;
760
0
    code = fn_common_scale((gs_function_t *)psfn, (const gs_function_t *)pfn,
761
0
                           pranges, mem);
762
0
    if (code < 0) {
763
0
        gs_function_free((gs_function_t *)psfn, true, mem);
764
0
        return code;
765
0
    }
766
0
    memcpy(ops, pfn->params.ops.data, pfn->params.ops.size - 1); /* minus return */
767
0
    p = ops + pfn->params.ops.size - 1;
768
0
    for (i = n; --i >= 0; ) {
769
0
        float base = pranges[i].rmin;
770
0
        float factor = pranges[i].rmax - base;
771
772
0
        if (factor != 1) {
773
0
            p[0] = PtCr_float; memcpy(p + 1, &factor, sizeof(float));
774
0
            p += 1 + sizeof(float);
775
0
            *p++ = PtCr_mul;
776
0
        }
777
0
        if (base != 0) {
778
0
            p[0] = PtCr_float; memcpy(p + 1, &base, sizeof(float));
779
0
            p += 1 + sizeof(float);
780
0
            *p++ = PtCr_add;
781
0
        }
782
0
        if (n != 1) {
783
0
            p[0] = PtCr_byte; p[1] = (byte)n;
784
0
            p[2] = PtCr_byte; p[3] = 1;
785
0
            p[4] = PtCr_roll;
786
0
            p += 5;
787
0
        }
788
0
    }
789
0
    *p++ = PtCr_return;
790
0
    psfn->params.ops.size = p - ops;
791
0
    psfn->params.ops.data =
792
0
        gs_resize_string(mem, ops, opsize, psfn->params.ops.size,
793
0
                         "fn_PtCr_make_scaled");
794
0
    *ppsfn = psfn;
795
0
    return 0;
796
0
}
797
798
/* Free the parameters of a PostScript Calculator function. */
799
void
800
gs_function_PtCr_free_params(gs_function_PtCr_params_t * params, gs_memory_t * mem)
801
0
{
802
0
    gs_free_const_string(mem, params->ops.data, params->ops.size, "ops");
803
0
    params->ops.data = NULL;
804
0
    params->ops.size = 0;
805
0
    fn_common_free_params((gs_function_params_t *) params, mem);
806
0
}
807
808
/* Serialize. */
809
static int
810
gs_function_PtCr_serialize(const gs_function_t * pfn, stream *s)
811
0
{
812
0
    uint n;
813
0
    const gs_function_PtCr_params_t * p = (const gs_function_PtCr_params_t *)&pfn->params;
814
0
    int code = fn_common_serialize(pfn, s);
815
816
0
    if (code < 0)
817
0
        return code;
818
0
    code = sputs(s, (const byte *)&p->ops.size, sizeof(p->ops.size), &n);
819
0
    if (code < 0)
820
0
        return code;
821
0
    return sputs(s, p->ops.data, p->ops.size, &n);
822
0
}
823
824
/* Allocate and initialize a PostScript Calculator function. */
825
int
826
gs_function_PtCr_init(gs_function_t ** ppfn,
827
                  const gs_function_PtCr_params_t * params, gs_memory_t * mem)
828
0
{
829
0
    static const gs_function_head_t function_PtCr_head = {
830
0
        function_type_PostScript_Calculator,
831
0
        {
832
0
            (fn_evaluate_proc_t) fn_PtCr_evaluate,
833
0
            (fn_is_monotonic_proc_t) fn_PtCr_is_monotonic,
834
0
            (fn_get_info_proc_t) fn_PtCr_get_info,
835
0
            fn_common_get_params,
836
0
            (fn_make_scaled_proc_t) fn_PtCr_make_scaled,
837
0
            (fn_free_params_proc_t) gs_function_PtCr_free_params,
838
0
            fn_common_free,
839
0
            (fn_serialize_proc_t) gs_function_PtCr_serialize,
840
0
        }
841
0
    };
842
0
    int code;
843
844
0
    *ppfn = 0;      /* in case of error */
845
0
    code = fn_check_mnDR((const gs_function_params_t *)params,
846
0
                         params->m, params->n);
847
0
    if (code < 0)
848
0
        return code;
849
0
    if (params->m > MAX_VSTACK || params->n > MAX_VSTACK)
850
0
        return_error(gs_error_limitcheck);
851
    /*
852
     * Pre-validate the operation string to reduce evaluation overhead.
853
     */
854
0
    {
855
0
        const byte *p = params->ops.data;
856
857
0
        for (; *p != PtCr_return; ++p)
858
0
            switch ((gs_PtCr_opcode_t)*p) {
859
0
            case PtCr_byte:
860
0
                ++p; break;
861
0
            case PtCr_int:
862
0
                p += sizeof(int); break;
863
0
            case PtCr_float:
864
0
                p += sizeof(float); break;
865
0
            case PtCr_repeat:
866
0
            case PtCr_if:
867
0
            case PtCr_else:
868
0
                p += 2;
869
0
            case PtCr_repeat_end:
870
0
            case PtCr_true:
871
0
            case PtCr_false:
872
0
                break;
873
0
            default:
874
0
                if (*p >= PtCr_NUM_OPS)
875
0
                    return_error(gs_error_rangecheck);
876
0
            }
877
0
        if (p != params->ops.data + params->ops.size - 1)
878
0
            return_error(gs_error_rangecheck);
879
0
    }
880
0
    {
881
0
        gs_function_PtCr_t *pfn =
882
0
            gs_alloc_struct(mem, gs_function_PtCr_t, &st_function_PtCr,
883
0
                            "gs_function_PtCr_init");
884
885
0
        if (pfn == 0)
886
0
            return_error(gs_error_VMerror);
887
0
        pfn->params = *params;
888
        /*
889
         * We claim to have a DataSource, in order to write the function
890
         * definition in symbolic form for embedding in PDF files.
891
         * ****** THIS IS A HACK. ******
892
         */
893
0
        data_source_init_string2(&pfn->data_source, NULL, 0);
894
0
        pfn->data_source.access = calc_access;
895
0
        pfn->head = function_PtCr_head;
896
0
        *ppfn = (gs_function_t *) pfn;
897
0
    }
898
0
    return 0;
899
0
}