Coverage Report

Created: 2025-06-10 07:27

/src/ghostpdl/psi/zdict.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
/* Dictionary operators */
18
#include "ghost.h"
19
#include "oper.h"
20
#include "iddict.h"
21
#include "dstack.h"
22
#include "ilevel.h"   /* for [count]dictstack */
23
#include "iname.h"    /* for dict_find_name */
24
#include "ipacked.h"    /* for inline dict lookup */
25
#include "ivmspace.h"
26
#include "store.h"
27
#include "iscan.h"              /* for SCAN_PDF_RULES */
28
29
/* <int> dict <dict> */
30
int
31
zdict(i_ctx_t *i_ctx_p)
32
40.1M
{
33
40.1M
    os_ptr op = osp;
34
35
40.1M
    check_op(1);
36
40.1M
    check_type(*op, t_integer);
37
40.1M
    if (op->value.intval < 0)
38
34
        return_error(gs_error_rangecheck);
39
40.1M
    return dict_create((uint) op->value.intval, op);
40
40.1M
}
41
42
/* <dict> maxlength <int> */
43
static int
44
zmaxlength(i_ctx_t *i_ctx_p)
45
91.5M
{
46
91.5M
    os_ptr op = osp;
47
48
91.5M
    check_op(1);
49
91.5M
    check_type(*op, t_dictionary);
50
91.5M
    check_dict_read(*op);
51
91.5M
    make_int(op, dict_maxlength(op));
52
91.5M
    return 0;
53
91.5M
}
54
55
/* <dict> begin - */
56
int
57
zbegin(i_ctx_t *i_ctx_p)
58
305M
{
59
305M
    os_ptr op = osp;
60
61
305M
    check_op(1);
62
305M
    check_type(*op, t_dictionary);
63
305M
    check_dict_read(*op);
64
305M
    if ( dsp == dstop ) {
65
521
        int code = ref_stack_extend(&d_stack, 1);
66
67
521
        if ( code < 0 ) {
68
4
            if (code == gs_error_dictstackoverflow) {
69
                /* Adobe doesn't restore the operand that caused stack */
70
                /* overflow. We do the same to match CET 20-02-02      */
71
4
                pop(1);
72
4
            }
73
4
            return code;
74
4
        }
75
521
    }
76
305M
    ++dsp;
77
305M
    ref_assign(dsp, op);
78
305M
    dict_set_top();
79
305M
    pop(1);
80
305M
    return 0;
81
305M
}
82
83
/* - end - */
84
int
85
zend(i_ctx_t *i_ctx_p)
86
305M
{
87
305M
    if (ref_stack_count_inline(&d_stack) == min_dstack_size) {
88
        /* We would underflow the d-stack. */
89
1.33k
        return_error(gs_error_dictstackunderflow);
90
1.33k
    }
91
305M
    while (dsp == dsbot) {
92
        /* We would underflow the current block. */
93
17
        ref_stack_pop_block(&d_stack);
94
17
    }
95
305M
    dsp--;
96
305M
    dict_set_top();
97
305M
    return 0;
98
305M
}
99
100
/* <key> <value> def - */
101
/*
102
 * We make this into a separate procedure because
103
 * the interpreter will almost always call it directly.
104
 */
105
int
106
zop_def(i_ctx_t *i_ctx_p)
107
396M
{
108
396M
    os_ptr op = osp;
109
396M
    os_ptr op1 = op - 1;
110
396M
    ref *pvslot;
111
112
396M
    check_op(2);
113
    /* The following combines a check_op(2) with a type check. */
114
396M
    switch (r_type(op1)) {
115
388M
        case t_name: {
116
            /* We can use the fast single-probe lookup here. */
117
388M
            uint nidx = name_index(imemory, op1);
118
388M
            uint htemp;
119
120
388M
            if_dict_find_name_by_index_top(nidx, htemp, pvslot) {
121
4.89M
                if (dtop_can_store(op))
122
4.89M
                    goto ra;
123
4.89M
            }
124
383M
            break;   /* handle all slower cases */
125
388M
            }
126
383M
        case t_null:
127
3
            return_error(gs_error_typecheck);
128
0
        case t__invalid:
129
0
            return_error(gs_error_stackunderflow);
130
396M
    }
131
    /*
132
     * Combine the check for a writable top dictionary with
133
     * the global/local store check.  See dstack.h for details.
134
     */
135
392M
    if (!dtop_can_store(op)) {
136
0
        check_dict_write(*dsp);
137
        /*
138
         * If the dictionary is writable, the problem must be
139
         * an invalid store.
140
         */
141
0
        return_error(gs_error_invalidaccess);
142
0
    }
143
    /*
144
     * Save a level of procedure call in the common (redefinition)
145
     * case.  With the current interfaces, we pay a double lookup
146
     * in the uncommon case.
147
     */
148
392M
    if (dict_find(dsp, op1, &pvslot) <= 0)
149
369M
        return idict_put(dsp, op1, op);
150
27.7M
ra:
151
27.7M
    if ((pvslot->tas.type_attrs & (&i_ctx_p->memory)->test_mask) == 0)
152
475k
        alloc_save_change(idmemory, &dsp->value.pdict->values, (ref_packed *)pvslot, "dict_put(value)");
153
27.7M
    ref_assign_new_inline(pvslot,op);
154
155
27.7M
    return 0;
156
392M
}
157
int
158
zdef(i_ctx_t *i_ctx_p)
159
0
{
160
0
    int code = zop_def(i_ctx_p);
161
162
0
    if (code >= 0) {
163
0
        pop(2);
164
0
    }
165
0
    return code;
166
0
}
167
168
/* <key> load <value> */
169
static int
170
zload(i_ctx_t *i_ctx_p)
171
296M
{
172
296M
    os_ptr op = osp;
173
296M
    ref *pvalue;
174
175
296M
    check_op(1);
176
296M
    switch (r_type(op)) {
177
296M
        case t_name:
178
            /* Use the fast lookup. */
179
296M
            if ((pvalue = dict_find_name(op)) == 0)
180
13
                return_error(gs_error_undefined);
181
296M
            ref_assign(op, pvalue);
182
296M
            return 0;
183
0
        case t_null:
184
0
            return_error(gs_error_typecheck);
185
0
        case t__invalid:
186
0
            return_error(gs_error_stackunderflow);
187
18
        default: {
188
                /* Use an explicit loop. */
189
18
                uint size = ref_stack_count(&d_stack);
190
18
                uint i;
191
192
70
                for (i = 0; i < size; i++) {
193
53
                    ref *dp = ref_stack_index(&d_stack, i);
194
195
53
                    if (dp == NULL)
196
0
                        return_error(gs_error_stackunderflow);
197
198
53
                    check_dict_read(*dp);
199
53
                    if (dict_find(dp, op, &pvalue) > 0) {
200
1
                        ref_assign(op, pvalue);
201
1
                        return 0;
202
1
                    }
203
53
                }
204
18
                return_error(gs_error_undefined);
205
18
            }
206
296M
    }
207
296M
}
208
209
/* get - implemented in zgeneric.c */
210
211
/* put - implemented in zgeneric.c */
212
213
/* <dict> <key> .undef - */
214
/* <dict> <key> undef - */
215
static int
216
zundef(i_ctx_t *i_ctx_p)
217
23.1M
{
218
23.1M
    os_ptr op = osp;
219
23.1M
    os_ptr op1 = op - 1;
220
23.1M
    int code;
221
222
23.1M
    check_op(2);
223
23.1M
    check_type(*op1, t_dictionary);
224
23.1M
    check_dict_write(*op1);
225
23.1M
    code = idict_undef(op1, op);
226
23.1M
    if (code < 0 && code != gs_error_undefined) /* ignore undefined error */
227
0
        return code;
228
23.1M
    pop(2);
229
23.1M
    return 0;
230
23.1M
}
231
232
/* <dict> <key> known <bool> */
233
static int
234
zknown(i_ctx_t *i_ctx_p)
235
359M
{
236
359M
    os_ptr op = osp;
237
359M
    register os_ptr op1 = op - 1;
238
359M
    ref *pvalue;
239
359M
    int code;
240
241
359M
    check_op(2);
242
359M
    check_type(*op1, t_dictionary);
243
359M
    check_dict_read(*op1);
244
359M
    code = dict_find(op1, op, &pvalue);
245
359M
    switch (code) {
246
17.2M
    case gs_error_dictfull:
247
17.2M
        code = 0;
248
359M
    case 0: case 1:
249
359M
        break;
250
0
    default:
251
0
        return code;
252
359M
    }
253
359M
    make_bool(op1, code);
254
359M
    pop(1);
255
359M
    return 0;
256
359M
}
257
258
/* <key> where <dict> true */
259
/* <key> where false */
260
int
261
zwhere(i_ctx_t *i_ctx_p)
262
16.0M
{
263
16.0M
    os_ptr op = osp;
264
16.0M
    ref_stack_enum_t rsenum;
265
266
16.0M
    check_op(1);
267
16.0M
    ref_stack_enum_begin(&rsenum, &d_stack);
268
16.0M
    do {
269
16.0M
        const ref *const bot = rsenum.ptr;
270
16.0M
        const ref *pdref = bot + rsenum.size;
271
16.0M
        ref *pvalue;
272
16.0M
        int code;
273
274
59.0M
        while (pdref-- > bot) {
275
51.3M
            check_dict_read(*pdref);
276
51.3M
            code = dict_find(pdref, op, &pvalue);
277
51.3M
            if (code < 0 && code != gs_error_dictfull)
278
0
                return code;
279
51.3M
            if (code > 0) {
280
8.35M
                push(1);
281
8.35M
                ref_assign(op - 1, pdref);
282
8.35M
                make_true(op);
283
8.35M
                return 0;
284
8.35M
            }
285
51.3M
        }
286
16.0M
    } while (ref_stack_enum_next(&rsenum));
287
7.65M
    make_false(op);
288
7.65M
    return 0;
289
16.0M
}
290
291
/* copy for dictionaries -- called from zcopy in zgeneric.c. */
292
/* Only the type of *op has been checked. */
293
int
294
zcopy_dict(i_ctx_t *i_ctx_p)
295
2.23M
{
296
2.23M
    os_ptr op = osp;
297
2.23M
    os_ptr op1 = op - 1;
298
2.23M
    int code;
299
300
2.23M
    check_op(2);
301
2.23M
    check_type(*op1, t_dictionary);
302
2.23M
    check_dict_read(*op1);
303
2.23M
    check_dict_write(*op);
304
2.23M
    if (!imemory->gs_lib_ctx->dict_auto_expand &&
305
2.23M
        (dict_length(op) != 0 || dict_maxlength(op) < dict_length(op1))
306
2.23M
        )
307
0
        return_error(gs_error_rangecheck);
308
2.23M
    code = idict_copy(op1, op);
309
2.23M
    if (code < 0)
310
0
        return code;
311
    /*
312
     * In Level 1 systems, we must copy the access attributes too.
313
     * The only possible effect this can have is to make the
314
     * copy read-only if the original dictionary is read-only.
315
     */
316
2.23M
    if (!level2_enabled)
317
2.23M
        r_copy_attrs(dict_access_ref(op), a_write, dict_access_ref(op1));
318
2.23M
    ref_assign(op1, op);
319
2.23M
    pop(1);
320
2.23M
    return 0;
321
2.23M
}
322
323
/* - currentdict <dict> */
324
static int
325
zcurrentdict(i_ctx_t *i_ctx_p)
326
82.4M
{
327
82.4M
    os_ptr op = osp;
328
329
82.4M
    push(1);
330
82.4M
    ref_assign(op, dsp);
331
82.4M
    return 0;
332
82.4M
}
333
334
/* - countdictstack <int> */
335
static int
336
zcountdictstack(i_ctx_t *i_ctx_p)
337
364k
{
338
364k
    os_ptr op = osp;
339
364k
    uint count = ref_stack_count(&d_stack);
340
341
364k
    push(1);
342
364k
    if (!level2_enabled)
343
0
        count--;   /* see dstack.h */
344
364k
    make_int(op, count);
345
364k
    return 0;
346
364k
}
347
348
/* <array> dictstack <subarray> */
349
static int
350
zdictstack(i_ctx_t *i_ctx_p)
351
362k
{
352
362k
    os_ptr op = osp;
353
362k
    uint count = ref_stack_count(&d_stack);
354
355
362k
    check_op(1);
356
362k
    if (!level2_enabled)
357
0
        count--;   /* see dstack.h */
358
362k
    if (!r_is_array(op))
359
362k
        return_op_typecheck(op);
360
362k
    if (r_size(op) < count)
361
0
        return_error(gs_error_rangecheck);
362
362k
    if (!r_has_type_attrs(op, t_array, a_write))
363
0
        return_error(gs_error_invalidaccess);
364
362k
    return ref_stack_store(&d_stack, op, count, 0, 0, true, idmemory,
365
362k
                           "dictstack");
366
362k
}
367
368
/* - cleardictstack - */
369
static int
370
zcleardictstack(i_ctx_t *i_ctx_p)
371
1.30k
{
372
1.33k
    while (zend(i_ctx_p) >= 0)
373
1.30k
        DO_NOTHING;
374
1.30k
    return 0;
375
1.30k
}
376
377
/* ------ Extensions ------ */
378
379
/* -mark- <key0> <value0> <key1> <value1> ... .dicttomark <dict> */
380
/* This is the Level 2 >> operator. */
381
static int
382
zdicttomark(i_ctx_t *i_ctx_p)
383
47.0M
{
384
47.0M
    uint count2 = ref_stack_counttomark(&o_stack);
385
47.0M
    ref rdict;
386
47.0M
    int code;
387
47.0M
    uint idx;
388
389
47.0M
    if (count2 == 0)
390
33
        return_error(gs_error_unmatchedmark);
391
47.0M
    count2--;
392
47.0M
    if ((count2 & 1) != 0)
393
17
        return_error(gs_error_rangecheck);
394
47.0M
    code = dict_create(count2 >> 1, &rdict);
395
47.0M
    if (code < 0)
396
0
        return code;
397
47.0M
    if ((i_ctx_p->scanner_options & SCAN_PDF_RULES) != 0) {
398
0
       for (idx = count2; idx > 0; idx -= 2) {
399
0
           code = idict_put(&rdict,
400
0
                            ref_stack_index(&o_stack, idx - 1),
401
0
                            ref_stack_index(&o_stack, idx - 2));
402
0
           if (code < 0) {         /* There's no way to free the dictionary -- too bad. */
403
0
               return code;
404
0
           }
405
0
       }
406
0
    }
407
47.0M
    else {
408
       /* << /a 1 /a 2 >> => << /a 1 >>, i.e., */
409
       /* we must enter the keys in top-to-bottom order. */
410
1.56G
       for (idx = 0; idx < count2; idx += 2) {
411
1.52G
           code = idict_put(&rdict,
412
1.52G
                            ref_stack_index(&o_stack, idx + 1),
413
1.52G
                            ref_stack_index(&o_stack, idx));
414
1.52G
           if (code < 0) {         /* There's no way to free the dictionary -- too bad. */
415
0
               return code;
416
0
           }
417
1.52G
       }
418
47.0M
    }
419
47.0M
    ref_stack_pop(&o_stack, count2);
420
47.0M
    ref_assign(osp, &rdict);
421
47.0M
    return code;
422
47.0M
}
423
424
/* <dict1> <dict2> .forcecopynew <dict2> */
425
/*
426
 * This operator is a special-purpose accelerator for use by 'restore' (see
427
 * gs_dps1.ps).  Note that this operator does *not* require that dict2 be
428
 * writable.  Hence it is in the same category of "dangerous" operators as
429
 * .forceput and .forceundef.
430
 */
431
static int
432
zforcecopynew(i_ctx_t *i_ctx_p)
433
206k
{
434
206k
    os_ptr op = osp;
435
206k
    os_ptr op1 = op - 1;
436
206k
    int code;
437
438
206k
    check_op(2);
439
206k
    check_type(*op1, t_dictionary);
440
206k
    check_dict_read(*op1);
441
206k
    check_type(*op, t_dictionary);
442
    /*check_dict_write(*op);*/  /* see above */
443
    /* This is only recognized in Level 2 mode. */
444
206k
    if (!imemory->gs_lib_ctx->dict_auto_expand)
445
0
        return_error(gs_error_undefined);
446
206k
    code = idict_copy_new(op1, op);
447
206k
    if (code < 0)
448
0
        return code;
449
206k
    ref_assign(op1, op);
450
206k
    pop(1);
451
206k
    return 0;
452
206k
}
453
454
/* <dict> <key> .forceundef - */
455
/*
456
 * This forces an "undef" even if the dictionary is not writable.
457
 * Like .forceput, it is meant to be used only in a few special situations,
458
 * and should not be accessible by name after initialization.
459
 */
460
static int
461
zforceundef(i_ctx_t *i_ctx_p)
462
79.6M
{
463
79.6M
    os_ptr op = osp;
464
465
79.6M
    check_op(2);
466
79.6M
    check_type(op[-1], t_dictionary);
467
    /* Don't check_dict_write */
468
79.6M
    idict_undef(op - 1, op); /* ignore undefined error */
469
79.6M
    pop(2);
470
79.6M
    return 0;
471
79.6M
}
472
473
/* <dict> <key> .knownget <value> true */
474
/* <dict> <key> .knownget false */
475
static int
476
zknownget(i_ctx_t *i_ctx_p)
477
743M
{
478
743M
    os_ptr op = osp;
479
743M
    register os_ptr op1 = op - 1;
480
743M
    ref *pvalue;
481
482
743M
    check_op(2);
483
743M
    check_type(*op1, t_dictionary);
484
743M
    check_dict_read(*op1);
485
743M
    if (dict_find(op1, op, &pvalue) <= 0) {
486
184M
        make_false(op1);
487
184M
        pop(1);
488
559M
    } else {
489
559M
        ref_assign(op1, pvalue);
490
559M
        make_true(op);
491
559M
    }
492
743M
    return 0;
493
743M
}
494
495
/* <dict> <key> .knownundef <bool> */
496
static int
497
zknownundef(i_ctx_t *i_ctx_p)
498
0
{
499
0
    os_ptr op = osp;
500
0
    os_ptr op1 = op - 1;
501
0
    int code;
502
503
0
    check_op(2);
504
0
    check_type(*op1, t_dictionary);
505
0
    check_dict_write(*op1);
506
0
    code = idict_undef(op1, op);
507
0
    make_bool(op1, code == 0);
508
0
    pop(1);
509
0
    return 0;
510
0
}
511
512
/* <dict> <int> .setmaxlength - */
513
static int
514
zsetmaxlength(i_ctx_t *i_ctx_p)
515
11.1M
{
516
11.1M
    os_ptr op = osp;
517
11.1M
    os_ptr op1 = op - 1;
518
11.1M
    uint new_size;
519
11.1M
    int code;
520
521
11.1M
    check_op(2);
522
11.1M
    check_type(*op1, t_dictionary);
523
11.1M
    check_dict_write(*op1);
524
11.1M
    check_type(*op, t_integer);
525
11.1M
    if (op->value.intval < 0)
526
0
        return_error(gs_error_rangecheck);
527
11.1M
    new_size = (uint) op->value.intval;
528
11.1M
    if (dict_length(op - 1) > new_size)
529
0
        return_error(gs_error_dictfull);
530
11.1M
    code = idict_resize(op - 1, new_size);
531
11.1M
    if (code >= 0)
532
11.1M
        pop(2);
533
11.1M
    return code;
534
11.1M
}
535
536
/* ------ Initialization procedure ------ */
537
538
/* We need to split the table because of the 16-element limit. */
539
const op_def zdict1_op_defs[] = {
540
    {"0cleardictstack", zcleardictstack},
541
    {"1begin", zbegin},
542
    {"0countdictstack", zcountdictstack},
543
    {"0currentdict", zcurrentdict},
544
    {"2def", zdef},
545
    {"1dict", zdict},
546
    {"0dictstack", zdictstack},
547
    {"0end", zend},
548
    {"2known", zknown},
549
    {"1load", zload},
550
    {"1maxlength", zmaxlength},
551
    {"2.undef", zundef},  /* we need this even in Level 1 */
552
    {"1where", zwhere},
553
    op_def_end(0)
554
};
555
const op_def zdict2_op_defs[] = {
556
                /* Extensions */
557
    {"1.dicttomark", zdicttomark},
558
    {"2.forcecopynew", zforcecopynew},
559
    {"2.forceundef", zforceundef},
560
    {"2.knownget", zknownget},
561
    {"1.knownundef", zknownundef},
562
    {"2.setmaxlength", zsetmaxlength},
563
        /*
564
         * In Level 2, >> is a synonym for .dicttomark, and undef for
565
         * .undef.  By giving the former their own entries, they will not be
566
         * "eq" to .dicttomark and .undef, but that doesn't matter, since
567
         * we're doing this only for the sake of Adobe- compatible error
568
         * stacks.
569
         */
570
    op_def_begin_level2(),
571
    {"1>>", zdicttomark},
572
    {"2undef", zundef},
573
    op_def_end(0)
574
};