Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/psi/zmisc.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
/* Miscellaneous operators */
18
19
#include "errno_.h"
20
#include "memory_.h"
21
#include "string_.h"
22
#include "ghost.h"
23
#include "gp.h"
24
#include "oper.h"
25
#include "ialloc.h"
26
#include "idict.h"
27
#include "dstack.h"   /* for name lookup in bind */
28
#include "iname.h"
29
#include "ipacked.h"
30
#include "ivmspace.h"
31
#include "store.h"
32
#include "igstate.h"            /* for gs_currentcpsimode */
33
#include "memento.h"
34
#include "iscan.h"
35
36
/**********************************************************************/
37
38
/* <proc> bind <proc> */
39
static inline bool
40
r_is_ex_oper(const ref *rp)
41
3.71G
{
42
3.71G
    return (r_has_attr(rp, a_executable) &&
43
3.71G
            (r_btype(rp) == t_operator || r_type(rp) == t_oparray));
44
3.71G
}
45
static int
46
zbind(i_ctx_t *i_ctx_p)
47
200M
{
48
200M
    os_ptr op = osp;
49
200M
    uint depth = 1;
50
200M
    ref defn;
51
200M
    register os_ptr bsp;
52
53
200M
    switch (r_type(op)) {
54
720k
        case t_array:
55
720k
            if (!r_has_attr(op, a_write)) {
56
32
                return 0; /* per PLRM3 */
57
32
            }
58
121M
        case t_mixedarray:
59
143M
        case t_shortarray:
60
143M
            defn = *op;
61
143M
            break;
62
12.0M
        case t_oparray:
63
12.0M
            defn = *op->value.const_refs;
64
12.0M
            break;
65
45.2M
        default:
66
45.2M
            return_op_typecheck(op);
67
200M
    }
68
200M
    push(1);
69
155M
    *op = defn;
70
155M
    bsp = op;
71
    /*
72
     * We must not make the top-level procedure read-only,
73
     * but we must bind it even if it is read-only already.
74
     *
75
     * Here are the invariants for the following loop:
76
     *      `depth' elements have been pushed on the ostack;
77
     *      For i < depth, p = ref_stack_index(&o_stack, i):
78
     *        *p is an array (or packedarray) ref.
79
     */
80
1.89G
    while (depth) {
81
15.5G
        while (r_size(bsp)) {
82
13.7G
            ref_packed *const tpp = (ref_packed *)bsp->value.packed; /* break const */
83
84
13.7G
            r_dec_size(bsp, 1);
85
13.7G
            if (r_is_packed(tpp)) {
86
                /* Check for a packed executable name */
87
8.38G
                ushort elt = *tpp;
88
89
8.38G
                if (r_packed_is_exec_name(&elt)) {
90
2.71G
                    ref nref;
91
2.71G
                    ref *pvalue;
92
93
2.71G
                    name_index_ref(imemory, packed_name_index(&elt),
94
2.71G
                                   &nref);
95
2.71G
                    if ((pvalue = dict_find_name(&nref)) != 0 &&
96
2.71G
                        r_is_ex_oper(pvalue)
97
2.71G
                        ) {
98
2.41G
                        store_check_dest(bsp, pvalue);
99
                        /*
100
                         * Always save the change, since this can only
101
                         * happen once.
102
                         */
103
2.41G
                        ref_do_save(bsp, tpp, "bind");
104
2.41G
                        *tpp = pt_tag(pt_executable_operator) +
105
2.41G
                            op_index(pvalue);
106
2.41G
                    }
107
2.71G
                }
108
8.38G
                bsp->value.packed = tpp + 1;
109
8.38G
            } else {
110
5.41G
                ref *const tp = bsp->value.refs++;
111
112
5.41G
                switch (r_type(tp)) {
113
1.93G
                    case t_name:  /* bind the name if an operator */
114
1.93G
                        if (r_has_attr(tp, a_executable)) {
115
1.39G
                            ref *pvalue;
116
117
1.39G
                            if ((pvalue = dict_find_name(tp)) != 0 &&
118
1.39G
                                r_is_ex_oper(pvalue)
119
1.39G
                                ) {
120
750M
                                store_check_dest(bsp, pvalue);
121
750M
                                ref_assign_old(bsp, tp, pvalue, "bind");
122
750M
                            }
123
1.39G
                        }
124
1.93G
                        break;
125
1.93G
                    case t_array: /* push into array if writable */
126
15.7M
                        if (!r_has_attr(tp, a_write))
127
3.39M
                            break;
128
1.14G
                    case t_mixedarray:
129
1.58G
                    case t_shortarray:
130
1.58G
                        if (r_has_attr(tp, a_executable)) {
131
                            /* Make reference read-only */
132
1.58G
                            r_clear_attrs(tp, a_write);
133
1.58G
                            if (bsp >= ostop) {
134
                                /* Push a new stack block. */
135
0
                                ref temp;
136
0
                                int code;
137
138
0
                                temp = *tp;
139
0
                                osp = bsp;
140
0
                                code = ref_stack_push(&o_stack, 1);
141
0
                                if (code < 0) {
142
0
                                    ref_stack_pop(&o_stack, depth);
143
0
                                    return_error(code);
144
0
                                }
145
0
                                bsp = osp;
146
0
                                *bsp = temp;
147
0
                            } else
148
1.58G
                                *++bsp = *tp;
149
1.58G
                            depth++;
150
1.58G
                        }
151
5.41G
                }
152
5.41G
            }
153
13.7G
        }
154
1.73G
        bsp--;
155
1.73G
        depth--;
156
1.73G
        if (bsp < osbot) { /* Pop back to the previous stack block. */
157
0
            osp = bsp;
158
0
            ref_stack_pop_block(&o_stack);
159
0
            bsp = osp;
160
0
        }
161
1.73G
    }
162
155M
    osp = bsp;
163
155M
    return 0;
164
155M
}
165
166
/* - serialnumber <int> */
167
static int
168
zserialnumber(i_ctx_t *i_ctx_p)
169
8
{
170
8
    os_ptr op = osp;
171
172
8
    push(1);
173
8
    make_int(op, gp_serialnumber());
174
8
    return 0;
175
8
}
176
177
/* - realtime <int> */
178
static int
179
zrealtime(i_ctx_t *i_ctx_p)
180
14
{
181
14
    os_ptr op = osp;
182
14
    long secs_ns[2];
183
14
    gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(imemory);
184
185
14
    gp_get_realtime(secs_ns);
186
14
    secs_ns[1] -= libctx->real_time_0[1];
187
14
    secs_ns[0] -= libctx->real_time_0[0];
188
14
    push(1);
189
14
    make_int(op, secs_ns[0] * 1000 + secs_ns[1] / 1000000);
190
14
    return 0;
191
14
}
192
193
/* - usertime <int> */
194
static int
195
zusertime(i_ctx_t *i_ctx_p)
196
2.33k
{
197
2.33k
    gs_context_state_t *current = (gs_context_state_t *)i_ctx_p;
198
2.33k
    os_ptr op = osp;
199
2.33k
    long secs_ns[2];
200
201
2.33k
    gp_get_usertime(secs_ns);
202
2.33k
    if (!current->usertime_inited) {
203
517
        current->usertime_inited = true;
204
517
        current->usertime_0[0] = secs_ns[0];
205
517
        current->usertime_0[1] = secs_ns[1];
206
517
    }
207
2.33k
    secs_ns[0] -= current->usertime_0[0];
208
2.33k
    secs_ns[1] -= current->usertime_0[1];
209
2.33k
    push(1);
210
2.33k
    make_int(op, secs_ns[0] * 1000 + secs_ns[1] / 1000000);
211
2.33k
    return 0;
212
2.33k
}
213
214
/* ---------------- Non-standard operators ---------------- */
215
216
/* <string> getenv <value_string> true */
217
/* <string> getenv false */
218
static int
219
zgetenv(i_ctx_t *i_ctx_p)
220
624k
{
221
624k
    os_ptr op = osp;
222
624k
    char *str;
223
624k
    byte *value;
224
624k
    int len = 0;
225
226
624k
    check_read_type(*op, t_string);
227
624k
    str = ref_to_string(op, imemory, "getenv key");
228
624k
    if (str == 0)
229
0
        return_error(gs_error_VMerror);
230
624k
    if (gp_getenv(str, (char *)0, &len) > 0) { /* key missing */
231
624k
        ifree_string((byte *) str, r_size(op) + 1, "getenv key");
232
624k
        make_false(op);
233
624k
        return 0;
234
624k
    }
235
0
    value = ialloc_string(len, "getenv value");
236
0
    if (value == 0) {
237
0
        ifree_string((byte *) str, r_size(op) + 1, "getenv key");
238
0
        return_error(gs_error_VMerror);
239
0
    }
240
0
    DISCARD(gp_getenv(str, (char *)value, &len));  /* can't fail */
241
0
    ifree_string((byte *) str, r_size(op) + 1, "getenv key");
242
    /* Delete the stupid C string terminator. */
243
0
    value = iresize_string(value, len, len - 1,
244
0
                           "getenv value"); /* can't fail */
245
0
    push(1);
246
0
    make_string(op - 1, a_all | icurrent_space, len - 1, value);
247
0
    make_true(op);
248
0
    return 0;
249
0
}
250
251
/* - .defaultpapersize <string> true */
252
/* - .defaultpapersize false */
253
static int
254
zdefaultpapersize(i_ctx_t *i_ctx_p)
255
89.2k
{
256
89.2k
    os_ptr op = osp;
257
89.2k
    byte *value;
258
89.2k
    int len = 0;
259
260
89.2k
    if (gp_defaultpapersize((char *)0, &len) > 0) {
261
        /* no default paper size */
262
89.2k
        push(1);
263
89.2k
        make_false(op);
264
89.2k
        return 0;
265
89.2k
    }
266
267
0
    value = ialloc_string(len, "defaultpapersize value");
268
0
    if (value == 0) {
269
0
        return_error(gs_error_VMerror);
270
0
    }
271
0
    DISCARD(gp_defaultpapersize((char *)value, &len)); /* can't fail */
272
    /* Delete the stupid C string terminator. */
273
0
    value = iresize_string(value, len, len - 1,
274
0
                           "defaultpapersize value"); /* can't fail */
275
0
    push(2);
276
0
    make_string(op - 1, a_all | icurrent_space, len - 1, value);
277
0
    make_true(op);
278
0
    return 0;
279
0
}
280
281
/* <name> <proc> .makeoperator <oper> */
282
static int
283
zmakeoperator(i_ctx_t *i_ctx_p)
284
17.2M
{
285
17.2M
    os_ptr op = osp;
286
17.2M
    op_array_table *opt;
287
17.2M
    uint count;
288
17.2M
    ref *tab;
289
290
17.2M
    check_type(op[-1], t_name);
291
17.2M
    check_proc(*op);
292
17.2M
    switch (r_space(op)) {
293
17.2M
        case avm_global:
294
17.2M
            opt = &i_ctx_p->op_array_table_global;
295
17.2M
            break;
296
0
        case avm_local:
297
0
            opt = &i_ctx_p->op_array_table_local;
298
0
            break;
299
0
        default:
300
0
            return_error(gs_error_invalidaccess);
301
17.2M
    }
302
17.2M
    count = opt->count;
303
17.2M
    tab = opt->table.value.refs;
304
    /*
305
     * restore doesn't reset op_array_table.count, but it does
306
     * remove entries from op_array_table.table.  Since we fill
307
     * the table in order, we can detect that a restore has occurred
308
     * by checking whether what should be the most recent entry
309
     * is occupied.  If not, we scan backwards over the vacated entries
310
     * to find the true end of the table.
311
     */
312
17.2M
    while (count > 0 && r_has_type(&tab[count - 1], t_null))
313
0
        --count;
314
17.2M
    if (count == r_size(&opt->table))
315
0
        return_error(gs_error_limitcheck);
316
17.2M
    ref_assign_old(&opt->table, &tab[count], op, "makeoperator");
317
17.2M
    opt->nx_table[count] = name_index(imemory, op - 1);
318
17.2M
    op_index_ref(imemory, opt->base_index + count, op - 1);
319
17.2M
    opt->count = count + 1;
320
17.2M
    pop(1);
321
17.2M
    return 0;
322
17.2M
}
323
324
/* - .oserrno <int> */
325
static int
326
zoserrno(i_ctx_t *i_ctx_p)
327
35.0k
{
328
35.0k
    os_ptr op = osp;
329
330
35.0k
    push(1);
331
35.0k
    make_int(op, errno);
332
35.0k
    return 0;
333
35.0k
}
334
335
/* <int> .setoserrno - */
336
static int
337
zsetoserrno(i_ctx_t *i_ctx_p)
338
213k
{
339
213k
    os_ptr op = osp;
340
341
213k
    check_type(*op, t_integer);
342
213k
    errno = op->value.intval;
343
213k
    pop(1);
344
213k
    return 0;
345
213k
}
346
347
/* <int> .oserrorstring <string> true */
348
/* <int> .oserrorstring false */
349
static int
350
zoserrorstring(i_ctx_t *i_ctx_p)
351
34.8k
{
352
34.8k
    os_ptr op = osp;
353
34.8k
    const char *str;
354
34.8k
    int code;
355
34.8k
    uint len;
356
34.8k
    byte ch;
357
358
34.8k
    check_type(*op, t_integer);
359
34.8k
    str = gp_strerror((int)op->value.intval);
360
34.8k
    if (str == 0 || (len = strlen(str)) == 0) {
361
0
        make_false(op);
362
0
        return 0;
363
0
    }
364
34.8k
    check_ostack(1);
365
34.8k
    code = string_to_ref(str, op, iimemory, ".oserrorstring");
366
34.8k
    if (code < 0)
367
0
        return code;
368
    /* Strip trailing end-of-line characters. */
369
34.8k
    while ((len = r_size(op)) != 0 &&
370
34.8k
           ((ch = op->value.bytes[--len]) == '\r' || ch == '\n')
371
34.8k
        )
372
0
        r_dec_size(op, 1);
373
34.8k
    push(1);
374
34.8k
    make_true(op);
375
34.8k
    return 0;
376
34.8k
}
377
378
/* <string> <bool> .setdebug - */
379
static int
380
zsetdebug(i_ctx_t *i_ctx_p)
381
0
{
382
0
    os_ptr op = osp;
383
0
    check_read_type(op[-1], t_string);
384
0
    check_type(*op, t_boolean);
385
0
    {
386
0
        int i;
387
388
0
        for (i = 0; i < r_size(op - 1); i++)
389
0
            gs_debug[op[-1].value.bytes[i] & 127] =
390
0
                op->value.boolval;
391
0
    }
392
0
    pop(2);
393
0
    return 0;
394
0
}
395
396
/* .mementolistnew - */
397
static int
398
zmementolistnewblocks(i_ctx_t *i_ctx_p)
399
0
{
400
0
    Memento_listNewBlocks();
401
0
    return 0;
402
0
}
403
404
/* There are a few cases where a customer/user might want CPSI behavior
405
 * instead of the GS default behavior. cmyk_to_rgb and Type 1 char fill
406
 * method are two that have come up so far. This operator allows a PS
407
 * program to control the behavior without needing to recompile.
408
 */
409
/* <bool> .setCPSImode - */
410
static int
411
zsetCPSImode(i_ctx_t *i_ctx_p)
412
0
{
413
0
    os_ptr op = osp;
414
0
    check_type(*op, t_boolean);
415
0
    gs_setcpsimode(imemory, op->value.boolval);
416
0
    if (op->value.boolval) {
417
0
        i_ctx_p->scanner_options |= SCAN_CPSI_MODE;
418
0
    }
419
0
    else {
420
0
        i_ctx_p->scanner_options &= ~(int)SCAN_CPSI_MODE;
421
0
    }
422
0
    pop(1);
423
0
    return 0;
424
0
}
425
426
/* - .getCPSImode <bool> */
427
static int
428
zgetCPSImode(i_ctx_t *i_ctx_p)
429
9
{
430
9
    os_ptr op = osp;
431
432
9
    push(1);
433
9
    make_bool(op, gs_currentcpsimode(imemory));
434
9
    return 0;
435
9
}
436
437
/* <int> .setscanconverter - */
438
static int
439
zsetscanconverter(i_ctx_t *i_ctx_p)
440
0
{
441
0
    int val;
442
443
0
    os_ptr op = osp;
444
0
    if (r_has_type(op, t_boolean))
445
0
        val = (int)op->value.boolval;
446
0
    else if (r_has_type(op, t_integer))
447
0
        val = op->value.intval;
448
0
    else
449
0
        return_op_typecheck(op);
450
451
0
    gs_setscanconverter(igs, val);
452
0
    pop(1);
453
0
    return 0;
454
0
}
455
456
/* - .getscanconverter <int> */
457
static int
458
zgetscanconverter(i_ctx_t *i_ctx_p)
459
0
{
460
0
    os_ptr op = osp;
461
462
0
    push(1);
463
0
    make_int(op, gs_getscanconverter(imemory));
464
0
    return 0;
465
0
}
466
/* ------ Initialization procedure ------ */
467
468
const op_def zmisc_a_op_defs[] =
469
{
470
    {"1bind", zbind},
471
    {"1getenv", zgetenv},
472
    {"0.defaultpapersize", zdefaultpapersize},
473
    {"2.makeoperator", zmakeoperator},
474
    {"0.oserrno", zoserrno},
475
    {"1.oserrorstring", zoserrorstring},
476
    {"0realtime", zrealtime},
477
    {"0serialnumber", zserialnumber},
478
    {"2.setdebug", zsetdebug},
479
    {"0.mementolistnewblocks", zmementolistnewblocks},
480
    {"1.setoserrno", zsetoserrno},
481
    {"0usertime", zusertime},
482
    op_def_end(0)
483
};
484
485
const op_def zmisc_b_op_defs[] =
486
{
487
    {"1.setCPSImode", zsetCPSImode},
488
    {"0.getCPSImode", zgetCPSImode},
489
    {"1.setscanconverter", zsetscanconverter},
490
    {"0.getscanconverter", zgetscanconverter},
491
    op_def_end(0)
492
};