Coverage Report

Created: 2026-07-24 07:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/psi/iinit.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 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
/* Initialize internally known objects for Ghostscript interpreter */
18
#include "string_.h"
19
#include "ghost.h"
20
#include "gscdefs.h"
21
#include "gsexit.h"
22
#include "gsstruct.h"
23
#include "ierrors.h"
24
#include "ialloc.h"
25
#include "iddict.h"
26
#include "dstack.h"
27
#include "ilevel.h"
28
#include "iinit.h"
29
#include "iname.h"
30
#include "interp.h"
31
#include "ipacked.h"
32
#include "iparray.h"
33
#include "iutil.h"
34
#include "ivmspace.h"
35
#include "opdef.h"
36
#include "store.h"
37
#include "iconf.h"
38
#include "gxiodev.h"
39
40
/* Implementation parameters. */
41
/*
42
 * Define the (initial) sizes of the various system dictionaries.  We want
43
 * the sizes to be prime numbers large enough to cover all the operators,
44
 * plus everything in the init files, even if all the optional features are
45
 * selected.  Note that these sizes must be large enough to get us through
46
 * initialization, since we start up in Level 1 mode where dictionaries
47
 * don't expand automatically.
48
 */
49
/* The size of systemdict can be set in the makefile. */
50
#ifndef SYSTEMDICT_SIZE
51
0
#  define SYSTEMDICT_SIZE 631
52
#endif
53
#ifndef SYSTEMDICT_LEVEL2_SIZE
54
0
#  define SYSTEMDICT_LEVEL2_SIZE 983
55
#endif
56
#ifndef SYSTEMDICT_LL3_SIZE
57
174k
#  define SYSTEMDICT_LL3_SIZE 1123
58
#endif
59
/* The size of level2dict, if applicable, can be set in the makefile. */
60
#ifndef LEVEL2DICT_SIZE
61
#  define LEVEL2DICT_SIZE 251
62
#endif
63
/* Ditto the size of ll3dict. */
64
#ifndef LL3DICT_SIZE
65
#  define LL3DICT_SIZE 43
66
#endif
67
/* Ditto the size of userdict. */
68
#ifndef USERDICT_SIZE
69
#  define USERDICT_SIZE 211
70
#endif
71
/* Ditto the size of filterdict. */
72
#ifndef FILTERDICT_SIZE
73
#  define FILTERDICT_SIZE 43
74
#endif
75
/* Define an arbitrary size for the operator procedure tables. */
76
#ifndef OP_ARRAY_TABLE_SIZE
77
348k
#  define OP_ARRAY_TABLE_SIZE 300
78
#endif
79
#ifndef OP_ARRAY_TABLE_GLOBAL_SIZE
80
174k
#  define OP_ARRAY_TABLE_GLOBAL_SIZE OP_ARRAY_TABLE_SIZE
81
#endif
82
#ifndef OP_ARRAY_TABLE_LOCAL_SIZE
83
174k
#  define OP_ARRAY_TABLE_LOCAL_SIZE (OP_ARRAY_TABLE_SIZE / 2)
84
#endif
85
#define OP_ARRAY_TABLE_TOTAL_SIZE\
86
  (OP_ARRAY_TABLE_GLOBAL_SIZE + OP_ARRAY_TABLE_LOCAL_SIZE)
87
88
/* Define the list of error names. */
89
const char *const gs_error_names[] =
90
{
91
    ERROR_NAMES
92
};
93
94
/* Enter a name and value into a dictionary. */
95
static int
96
i_initial_enter_name_in(i_ctx_t *i_ctx_p, ref *pdict, const char *nstr,
97
                        const ref * pref)
98
104M
{
99
104M
    int code = idict_put_string(pdict, nstr, pref);
100
101
104M
    if (code < 0)
102
0
        lprintf4("initial_enter failed (%d), entering /%s in -dict:%u/%u-\n",
103
104M
                 code, nstr, dict_length(pdict), dict_maxlength(pdict));
104
104M
    return code;
105
104M
}
106
int
107
i_initial_enter_name(i_ctx_t *i_ctx_p, const char *nstr, const ref * pref)
108
3.66M
{
109
3.66M
    return i_initial_enter_name_in(i_ctx_p, systemdict, nstr, pref);
110
3.66M
}
111
112
/* Enter a name and value into a dictionary. */
113
static int
114
i_initial_enter_name_copy_in(i_ctx_t *i_ctx_p, ref *pdict, const char *nstr,
115
                             const ref * pref)
116
2.55M
{
117
2.55M
    int code = idict_put_string_copy(pdict, nstr, pref);
118
119
2.55M
    if (code < 0)
120
0
        lprintf4("initial_enter failed (%d), entering /%s in -dict:%u/%u-\n",
121
2.55M
                 code, nstr, dict_length(pdict), dict_maxlength(pdict));
122
2.55M
    return code;
123
2.55M
}
124
int
125
i_initial_enter_name_copy(i_ctx_t *i_ctx_p, const char *nstr, const ref * pref)
126
2.55M
{
127
2.55M
    return i_initial_enter_name_copy_in(i_ctx_p, systemdict, nstr, pref);
128
2.55M
}
129
130
/* Remove a name from systemdict. */
131
void
132
i_initial_remove_name(i_ctx_t *i_ctx_p, const char *nstr)
133
0
{
134
0
    ref nref;
135
136
0
    if (name_ref(imemory, (const byte *)nstr, strlen(nstr), &nref, -1) >= 0)
137
0
        idict_undef(systemdict, &nref);
138
0
}
139
140
/* Define the names and sizes of the initial dictionaries. */
141
/* The names are used to create references in systemdict. */
142
const struct {
143
    const char *name;
144
    uint size;
145
    bool local;
146
} initial_dictionaries[] = {
147
#ifdef INITIAL_DICTIONARIES
148
    INITIAL_DICTIONARIES
149
#else
150
    /* systemdict is created and named automagically */
151
    {
152
        "level2dict", LEVEL2DICT_SIZE, false
153
    },
154
    {
155
        "ll3dict", LL3DICT_SIZE, false
156
    },
157
    {
158
        "globaldict", 0, false
159
    },
160
    {
161
        "userdict", USERDICT_SIZE, true
162
    },
163
    {
164
        "filterdict", FILTERDICT_SIZE, false
165
    },
166
#endif
167
};
168
/* systemdict and globaldict are magically inserted at the bottom */
169
const char *const initial_dstack[] =
170
{
171
#ifdef INITIAL_DSTACK
172
    INITIAL_DSTACK
173
#else
174
    "userdict"
175
#endif
176
};
177
178
174k
#define MIN_DSTACK_SIZE (countof(initial_dstack) + 1)   /* +1 for systemdict */
179
180
/*
181
 * Detect whether we have any Level 2 or LanguageLevel 3 operators.
182
 * We export this for gs_init1 in imain.c.
183
 * This is slow, but we only call it a couple of times.
184
 */
185
static int
186
gs_op_language_level(void)
187
348k
{
188
348k
    const op_def *const *tptr;
189
348k
    int level = 1;
190
191
35.9M
    for (tptr = op_defs_all; *tptr != 0; ++tptr) {
192
35.5M
        const op_def *def;
193
194
273M
        for (def = *tptr; def->oname != 0; ++def)
195
238M
            if (op_def_is_begin_dict(def)) {
196
9.77M
                if (!strcmp(def->oname, "level2dict"))
197
5.23M
                    level = max(level, 2);
198
4.53M
                else if (!strcmp(def->oname, "ll3dict"))
199
1.39M
                    level = max(level, 3);
200
9.77M
            }
201
35.5M
    }
202
348k
    return level;
203
348k
}
204
bool
205
gs_have_level2(void)
206
174k
{
207
174k
    return (gs_op_language_level() >= 2);
208
174k
}
209
210
/* Create an initial dictionary if necessary. */
211
static ref *
212
make_initial_dict(i_ctx_t *i_ctx_p, const char *iname, ref idicts[])
213
5.05M
{
214
5.05M
    int i;
215
216
    /* systemdict was created specially. */
217
5.05M
    if (!strcmp(iname, "systemdict"))
218
174k
        return systemdict;
219
11.6M
    for (i = 0; i < countof(initial_dictionaries); i++) {
220
11.6M
        const char *dname = initial_dictionaries[i].name;
221
11.6M
        const int dsize = initial_dictionaries[i].size;
222
223
11.6M
        if (!strcmp(iname, dname)) {
224
4.88M
            ref *dref = &idicts[i];
225
226
4.88M
            if (r_has_type(dref, t_null)) {
227
697k
                gs_ref_memory_t *mem =
228
697k
                    (initial_dictionaries[i].local ?
229
523k
                     iimemory_local : iimemory_global);
230
697k
                int code = dict_alloc(mem, dsize, dref);
231
232
697k
                if (code < 0)
233
0
                    return 0;   /* disaster */
234
697k
            }
235
4.88M
            return dref;
236
4.88M
        }
237
11.6M
    }
238
239
    /*
240
     * Name mentioned in some op_def, but not in initial_dictionaries.
241
     * Punt.
242
     */
243
0
    return 0;
244
4.88M
}
245
246
/* Initialize objects other than operators.  In particular, */
247
/* initialize the dictionaries that hold operator definitions. */
248
int
249
obj_init(i_ctx_t **pi_ctx_p, gs_dual_memory_t *idmem)
250
174k
{
251
174k
    int level = gs_op_language_level();
252
174k
    ref system_dict;
253
174k
    i_ctx_t *i_ctx_p;
254
174k
    int code;
255
256
    /*
257
     * Create systemdict.  The context machinery requires that
258
     * we do this before initializing the interpreter.
259
     */
260
174k
    code = dict_alloc(idmem->space_global,
261
174k
                      (level >= 3 ? SYSTEMDICT_LL3_SIZE :
262
174k
                       level >= 2 ? SYSTEMDICT_LEVEL2_SIZE : SYSTEMDICT_SIZE),
263
174k
                      &system_dict);
264
174k
    if (code < 0)
265
0
        return code;
266
267
    /* Initialize the interpreter. */
268
174k
    code = gs_interp_init(pi_ctx_p, &system_dict, idmem);
269
174k
    if (code < 0)
270
0
        return code;
271
174k
    i_ctx_p = *pi_ctx_p;
272
273
174k
    {
274
1.04M
#define icount countof(initial_dictionaries)
275
174k
        ref idicts[icount];
276
174k
        int i;
277
174k
        const op_def *const *tptr;
278
279
174k
        min_dstack_size = MIN_DSTACK_SIZE;
280
281
174k
        refset_null(idicts, icount);
282
283
        /* Put systemdict on the dictionary stack. */
284
174k
        if (level >= 2) {
285
174k
            dsp += 2;
286
            /*
287
             * For the moment, let globaldict be an alias for systemdict.
288
             */
289
174k
            dsp[-1] = system_dict;
290
174k
            min_dstack_size++;
291
174k
        } else {
292
0
            ++dsp;
293
0
        }
294
174k
        *dsp = system_dict;
295
296
        /* Create dictionaries which are to be homes for operators. */
297
17.9M
        for (tptr = op_defs_all; *tptr != 0; tptr++) {
298
17.7M
            const op_def *def;
299
300
136M
            for (def = *tptr; def->oname != 0; def++)
301
119M
                if (op_def_is_begin_dict(def)) {
302
4.88M
                    if (make_initial_dict(i_ctx_p, def->oname, idicts) == 0)
303
0
                        return_error(gs_error_VMerror);
304
4.88M
                }
305
17.7M
        }
306
307
        /* Set up the initial dstack. */
308
348k
        for (i = 0; i < countof(initial_dstack); i++) {
309
174k
            const char *dname = initial_dstack[i];
310
174k
            ref *r;
311
312
174k
            ++dsp;
313
174k
            if (!strcmp(dname, "userdict"))
314
174k
                dstack_userdict_index = dsp - dsbot;
315
174k
            r = make_initial_dict(i_ctx_p, dname, idicts);
316
174k
            if (r == NULL)
317
0
                return_error(gs_error_VMerror);
318
174k
            ref_assign(dsp, r);
319
174k
        }
320
321
        /* Enter names of referenced initial dictionaries into systemdict. */
322
174k
        i_initial_enter_name(i_ctx_p, "systemdict", systemdict);
323
1.04M
        for (i = 0; i < icount; i++) {
324
872k
            ref *idict = &idicts[i];
325
326
872k
            if (!r_has_type(idict, t_null)) {
327
                /*
328
                 * Note that we enter the dictionary in systemdict
329
                 * even if it is in local VM.  There is a special
330
                 * provision in the garbage collector for this:
331
                 * see ivmspace.h for more information.
332
                 * In order to do this, we must temporarily
333
                 * identify systemdict as local, so that the
334
                 * store check in dict_put won't fail.
335
                 */
336
697k
                uint save_space = r_space(systemdict);
337
338
697k
                r_set_space(systemdict, avm_local);
339
697k
                code = i_initial_enter_name(i_ctx_p, initial_dictionaries[i].name,
340
697k
                                            idict);
341
697k
                r_set_space(systemdict, save_space);
342
697k
                if (code < 0)
343
0
                    return code;
344
697k
            }
345
872k
        }
346
174k
#undef icount
347
174k
    }
348
349
174k
    gs_interp_reset(i_ctx_p);
350
351
174k
    {
352
174k
#ifdef PACIFY_VALGRIND
353
174k
        ref vnull = { 0 }, vtrue = { 0 }, vfalse = { 0 };
354
#else
355
        ref vnull, vtrue, vfalse;
356
#endif
357
358
174k
        make_null(&vnull);
359
174k
        make_true(&vtrue);
360
174k
        make_false(&vfalse);
361
174k
        if ((code = i_initial_enter_name(i_ctx_p, "null", &vnull)) < 0 ||
362
174k
            (code = i_initial_enter_name(i_ctx_p, "true", &vtrue)) < 0 ||
363
174k
            (code = i_initial_enter_name(i_ctx_p, "false", &vfalse)) < 0
364
174k
            )
365
0
            return code;
366
174k
    }
367
368
    /* Create the error name table */
369
174k
    {
370
174k
        int n = countof(gs_error_names);
371
174k
        int i;
372
174k
        ref era;
373
374
174k
        code = ialloc_ref_array(&era, a_readonly, n, "ErrorNames");
375
174k
        if (code < 0)
376
0
            return code;
377
5.75M
        for (i = 0; i < n; i++)
378
5.58M
          if ((code = name_enter_string(imemory, (const char *)gs_error_names[i],
379
5.58M
                                          era.value.refs + i)) < 0)
380
0
                return code;
381
174k
        return i_initial_enter_name(i_ctx_p, "ErrorNames", &era);
382
174k
    }
383
174k
}
384
385
/* Run the initialization procedures of the individual operator files. */
386
int
387
zop_init(i_ctx_t *i_ctx_p)
388
174k
{
389
174k
    const op_def *const *tptr;
390
174k
    int code;
391
392
    /* Because of a bug in Sun's SC1.0 compiler, */
393
    /* we have to spell out the typedef for op_def_ptr here: */
394
174k
    const op_def *def;
395
396
17.9M
    for (tptr = op_defs_all; *tptr != 0; tptr++) {
397
136M
        for (def = *tptr; def->oname != 0; def++)
398
119M
            DO_NOTHING;
399
17.7M
        if (def->proc != 0) {
400
697k
            code = def->proc(i_ctx_p);
401
697k
            if (code < 0) {
402
#ifdef DEBUG
403
                lprintf2("op_init proc "PRI_INTPTR" returned error %d!\n",
404
                         (intptr_t)def->proc, code);
405
#else
406
0
                lprintf("op_init proc returned error !\n");
407
0
#endif
408
0
                return code;
409
0
            }
410
697k
        }
411
17.7M
    }
412
413
    /* Initialize the predefined names other than operators. */
414
    /* Do this here in case op_init changed any of them. */
415
174k
    {
416
174k
        ref vcr, vpr, vpf, vre, vrd, vres;
417
418
174k
        make_const_string(&vcr, a_readonly | avm_foreign,
419
174k
                          strlen(gs_copyright), (const byte *)gs_copyright);
420
174k
        make_const_string(&vpr, a_readonly | avm_foreign,
421
174k
                          strlen(gs_product), (const byte *)gs_product);
422
174k
        make_const_string(&vpf, a_readonly | avm_foreign,
423
174k
                          strlen(gs_productfamily),
424
174k
                          (const byte *)gs_productfamily);
425
174k
        make_const_string(&vres, a_readonly | avm_foreign,
426
174k
                          strlen(GS_STRINGIZE(GS_DOT_VERSION)),
427
174k
                          (const byte *)GS_STRINGIZE(GS_DOT_VERSION));
428
174k
        make_int(&vre, gs_revision);
429
174k
        make_int(&vrd, gs_revisiondate);
430
174k
        if ((code = i_initial_enter_name(i_ctx_p, "copyright", &vcr)) < 0 ||
431
174k
            (code = i_initial_enter_name(i_ctx_p, "product", &vpr)) < 0 ||
432
174k
            (code = i_initial_enter_name(i_ctx_p, "productfamily", &vpf)) < 0 ||
433
174k
            (code = i_initial_enter_name(i_ctx_p, "revision", &vre)) < 0 ||
434
174k
            (code = i_initial_enter_name(i_ctx_p, "revisiondate", &vrd)) < 0 ||
435
174k
            (code = i_initial_enter_name(i_ctx_p, ".revisionstring", &vres)) < 0)
436
0
            return code;
437
174k
    }
438
439
174k
    return 0;
440
174k
}
441
442
/* Create an op_array table. */
443
static int
444
alloc_op_array_table(i_ctx_t *i_ctx_p, uint size, uint space,
445
                     op_array_table *opt)
446
348k
{
447
348k
    uint save_space = ialloc_space(idmemory);
448
348k
    int code;
449
450
348k
    ialloc_set_space(idmemory, space);
451
348k
    code = ialloc_ref_array(&opt->table, a_readonly, size,
452
348k
                            "op_array table");
453
348k
    ialloc_set_space(idmemory, save_space);
454
348k
    if (code < 0)
455
0
        return code;
456
348k
    refset_null(opt->table.value.refs, size);
457
348k
    opt->nx_table =
458
348k
        (ushort *) ialloc_byte_array(size, sizeof(ushort),
459
348k
                                     "op_array nx_table");
460
348k
    if (opt->nx_table == 0)
461
0
        return_error(gs_error_VMerror);
462
348k
    opt->count = 0;
463
348k
    opt->attrs = space | a_executable;
464
348k
    return 0;
465
348k
}
466
467
/* Initialize the operator table. */
468
int
469
op_init(i_ctx_t *i_ctx_p)
470
174k
{
471
174k
    const op_def *const *tptr;
472
174k
    int code;
473
474
    /* Enter each operator into the appropriate dictionary. */
475
476
17.9M
    for (tptr = op_defs_all; *tptr != 0; tptr++) {
477
17.7M
        ref *pdict = systemdict;
478
17.7M
        const op_def *def;
479
17.7M
        const char *nstr;
480
481
136M
        for (def = *tptr; (nstr = def->oname) != 0; def++)
482
119M
            if (op_def_is_begin_dict(def)) {
483
4.88M
                ref nref;
484
485
4.88M
                code = name_ref(imemory, (const byte *)nstr, strlen(nstr), &nref, -1);
486
4.88M
                if (code < 0)
487
0
                    return code;
488
4.88M
                if (!dict_find(systemdict, &nref, &pdict))
489
0
                    return_error(gs_error_Fatal);
490
4.88M
                if (!r_has_type(pdict, t_dictionary))
491
0
                    return_error(gs_error_Fatal);
492
114M
            } else {
493
114M
                ref oper;
494
114M
                uint index_in_table = def - *tptr;
495
114M
                uint opidx = (tptr - op_defs_all) * OP_DEFS_MAX_SIZE +
496
114M
                    index_in_table;
497
498
114M
                if (index_in_table >= OP_DEFS_MAX_SIZE) {
499
0
                    lprintf1("opdef overrun! %s\n", def->oname);
500
0
                    return_error(gs_error_Fatal);
501
0
                }
502
114M
                gs_interp_make_oper(&oper, def->proc, opidx);
503
                /* The first character of the name is a digit */
504
                /* giving the minimum acceptable number of operands. */
505
                /* Check to make sure it's within bounds. */
506
114M
                if (*nstr - '0' > gs_interp_max_op_num_args)
507
0
                    return_error(gs_error_Fatal);
508
114M
                nstr++;
509
                /*
510
                 * Skip internal operators, and the second occurrence of
511
                 * operators with special indices.
512
                 */
513
114M
                if (*nstr != '%' && r_size(&oper) == opidx) {
514
100M
                    code =
515
100M
                        i_initial_enter_name_in(i_ctx_p, pdict, nstr, &oper);
516
100M
                    if (code < 0)
517
0
                        return code;
518
100M
                }
519
114M
            }
520
17.7M
    }
521
    /* Allocate the tables for `operator' procedures. */
522
    /* Make one of them local so we can have local operators. */
523
174k
    if ((code = alloc_op_array_table(i_ctx_p, OP_ARRAY_TABLE_GLOBAL_SIZE,
524
174k
                                     avm_global,
525
174k
                                     &i_ctx_p->op_array_table_global) < 0))
526
0
        return code;
527
174k
    i_ctx_p->op_array_table_global.base_index = op_def_count;
528
174k
    if ((code = alloc_op_array_table(i_ctx_p, OP_ARRAY_TABLE_LOCAL_SIZE,
529
174k
                                     avm_local,
530
174k
                                     &i_ctx_p->op_array_table_local) < 0))
531
0
        return code;
532
174k
    i_ctx_p->op_array_table_local.base_index =
533
174k
        i_ctx_p->op_array_table_global.base_index +
534
174k
        r_size(&i_ctx_p->op_array_table_global.table);
535
536
174k
    return 0;
537
174k
}
538
539
#if defined(DEBUG_TRACE_PS_OPERATORS) || defined(DEBUG)
540
static const char *unknown_op_name = "unknown_op";
541
542
const char *
543
op_get_name_string(op_proc_t opproc)
544
{
545
    const op_def *const *tptr;
546
547
    for (tptr = op_defs_all; *tptr != 0; tptr++) {
548
        const op_def *def;
549
550
        for (def = *tptr; def->oname != 0; def++)
551
            if (!op_def_is_begin_dict(def)) {
552
                if (def->proc == opproc)
553
                    return def->oname;
554
            }
555
    }
556
    return unknown_op_name;
557
}
558
#endif
559
560
int
561
i_iodev_init(gs_dual_memory_t *dmem)
562
174k
{
563
174k
    int i;
564
174k
    int code;
565
174k
    gs_memory_t *mem = (gs_memory_t *)dmem->current;
566
567
174k
    code = gs_iodev_init(mem);
568
569
1.39M
    for (i = 0; i < i_io_device_table_count && code >= 0; i++) {
570
1.22M
        code = gs_iodev_register_dev(mem, i_io_device_table[i]);
571
1.22M
    }
572
573
174k
    return code;
574
174k
}
575
576
void
577
i_iodev_finit(gs_dual_memory_t *dmem)
578
174k
{
579
174k
    gs_iodev_finit((gs_memory_t *)dmem->current);
580
174k
}