Coverage Report

Created: 2025-06-10 06:59

/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
2.43M
{
33
2.43M
    os_ptr op = osp;
34
35
2.43M
    check_op(1);
36
2.43M
    check_type(*op, t_integer);
37
2.43M
    if (op->value.intval < 0)
38
1
        return_error(gs_error_rangecheck);
39
2.43M
    return dict_create((uint) op->value.intval, op);
40
2.43M
}
41
42
/* <dict> maxlength <int> */
43
static int
44
zmaxlength(i_ctx_t *i_ctx_p)
45
5.64M
{
46
5.64M
    os_ptr op = osp;
47
48
5.64M
    check_op(1);
49
5.64M
    check_type(*op, t_dictionary);
50
5.64M
    check_dict_read(*op);
51
5.64M
    make_int(op, dict_maxlength(op));
52
5.64M
    return 0;
53
5.64M
}
54
55
/* <dict> begin - */
56
int
57
zbegin(i_ctx_t *i_ctx_p)
58
19.5M
{
59
19.5M
    os_ptr op = osp;
60
61
19.5M
    check_op(1);
62
19.5M
    check_type(*op, t_dictionary);
63
19.5M
    check_dict_read(*op);
64
19.5M
    if ( dsp == dstop ) {
65
92
        int code = ref_stack_extend(&d_stack, 1);
66
67
92
        if ( code < 0 ) {
68
1
            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
1
                pop(1);
72
1
            }
73
1
            return code;
74
1
        }
75
92
    }
76
19.5M
    ++dsp;
77
19.5M
    ref_assign(dsp, op);
78
19.5M
    dict_set_top();
79
19.5M
    pop(1);
80
19.5M
    return 0;
81
19.5M
}
82
83
/* - end - */
84
int
85
zend(i_ctx_t *i_ctx_p)
86
19.4M
{
87
19.4M
    if (ref_stack_count_inline(&d_stack) == min_dstack_size) {
88
        /* We would underflow the d-stack. */
89
100
        return_error(gs_error_dictstackunderflow);
90
100
    }
91
19.4M
    while (dsp == dsbot) {
92
        /* We would underflow the current block. */
93
0
        ref_stack_pop_block(&d_stack);
94
0
    }
95
19.4M
    dsp--;
96
19.4M
    dict_set_top();
97
19.4M
    return 0;
98
19.4M
}
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
17.5M
{
108
17.5M
    os_ptr op = osp;
109
17.5M
    os_ptr op1 = op - 1;
110
17.5M
    ref *pvslot;
111
112
17.5M
    check_op(2);
113
    /* The following combines a check_op(2) with a type check. */
114
17.5M
    switch (r_type(op1)) {
115
17.0M
        case t_name: {
116
            /* We can use the fast single-probe lookup here. */
117
17.0M
            uint nidx = name_index(imemory, op1);
118
17.0M
            uint htemp;
119
120
17.0M
            if_dict_find_name_by_index_top(nidx, htemp, pvslot) {
121
377k
                if (dtop_can_store(op))
122
377k
                    goto ra;
123
377k
            }
124
16.6M
            break;   /* handle all slower cases */
125
17.0M
            }
126
16.6M
        case t_null:
127
0
            return_error(gs_error_typecheck);
128
0
        case t__invalid:
129
0
            return_error(gs_error_stackunderflow);
130
17.5M
    }
131
    /*
132
     * Combine the check for a writable top dictionary with
133
     * the global/local store check.  See dstack.h for details.
134
     */
135
17.1M
    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
17.1M
    if (dict_find(dsp, op1, &pvslot) <= 0)
149
15.4M
        return idict_put(dsp, op1, op);
150
2.08M
ra:
151
2.08M
    if ((pvslot->tas.type_attrs & (&i_ctx_p->memory)->test_mask) == 0)
152
20.0k
        alloc_save_change(idmemory, &dsp->value.pdict->values, (ref_packed *)pvslot, "dict_put(value)");
153
2.08M
    ref_assign_new_inline(pvslot,op);
154
155
2.08M
    return 0;
156
17.1M
}
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
18.3M
{
172
18.3M
    os_ptr op = osp;
173
18.3M
    ref *pvalue;
174
175
18.3M
    check_op(1);
176
18.3M
    switch (r_type(op)) {
177
18.3M
        case t_name:
178
            /* Use the fast lookup. */
179
18.3M
            if ((pvalue = dict_find_name(op)) == 0)
180
1
                return_error(gs_error_undefined);
181
18.3M
            ref_assign(op, pvalue);
182
18.3M
            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
3
        default: {
188
                /* Use an explicit loop. */
189
3
                uint size = ref_stack_count(&d_stack);
190
3
                uint i;
191
192
12
                for (i = 0; i < size; i++) {
193
9
                    ref *dp = ref_stack_index(&d_stack, i);
194
195
9
                    if (dp == NULL)
196
0
                        return_error(gs_error_stackunderflow);
197
198
9
                    check_dict_read(*dp);
199
9
                    if (dict_find(dp, op, &pvalue) > 0) {
200
0
                        ref_assign(op, pvalue);
201
0
                        return 0;
202
0
                    }
203
9
                }
204
3
                return_error(gs_error_undefined);
205
3
            }
206
18.3M
    }
207
18.3M
}
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
1.42M
{
218
1.42M
    os_ptr op = osp;
219
1.42M
    os_ptr op1 = op - 1;
220
1.42M
    int code;
221
222
1.42M
    check_op(2);
223
1.42M
    check_type(*op1, t_dictionary);
224
1.42M
    check_dict_write(*op1);
225
1.42M
    code = idict_undef(op1, op);
226
1.42M
    if (code < 0 && code != gs_error_undefined) /* ignore undefined error */
227
0
        return code;
228
1.42M
    pop(2);
229
1.42M
    return 0;
230
1.42M
}
231
232
/* <dict> <key> known <bool> */
233
static int
234
zknown(i_ctx_t *i_ctx_p)
235
22.0M
{
236
22.0M
    os_ptr op = osp;
237
22.0M
    register os_ptr op1 = op - 1;
238
22.0M
    ref *pvalue;
239
22.0M
    int code;
240
241
22.0M
    check_op(2);
242
22.0M
    check_type(*op1, t_dictionary);
243
22.0M
    check_dict_read(*op1);
244
22.0M
    code = dict_find(op1, op, &pvalue);
245
22.0M
    switch (code) {
246
1.11M
    case gs_error_dictfull:
247
1.11M
        code = 0;
248
22.0M
    case 0: case 1:
249
22.0M
        break;
250
0
    default:
251
0
        return code;
252
22.0M
    }
253
22.0M
    make_bool(op1, code);
254
22.0M
    pop(1);
255
22.0M
    return 0;
256
22.0M
}
257
258
/* <key> where <dict> true */
259
/* <key> where false */
260
int
261
zwhere(i_ctx_t *i_ctx_p)
262
988k
{
263
988k
    os_ptr op = osp;
264
988k
    ref_stack_enum_t rsenum;
265
266
988k
    check_op(1);
267
988k
    ref_stack_enum_begin(&rsenum, &d_stack);
268
988k
    do {
269
988k
        const ref *const bot = rsenum.ptr;
270
988k
        const ref *pdref = bot + rsenum.size;
271
988k
        ref *pvalue;
272
988k
        int code;
273
274
3.60M
        while (pdref-- > bot) {
275
3.14M
            check_dict_read(*pdref);
276
3.14M
            code = dict_find(pdref, op, &pvalue);
277
3.14M
            if (code < 0 && code != gs_error_dictfull)
278
0
                return code;
279
3.14M
            if (code > 0) {
280
528k
                push(1);
281
528k
                ref_assign(op - 1, pdref);
282
528k
                make_true(op);
283
528k
                return 0;
284
528k
            }
285
3.14M
        }
286
988k
    } while (ref_stack_enum_next(&rsenum));
287
459k
    make_false(op);
288
459k
    return 0;
289
988k
}
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
138k
{
296
138k
    os_ptr op = osp;
297
138k
    os_ptr op1 = op - 1;
298
138k
    int code;
299
300
138k
    check_op(2);
301
138k
    check_type(*op1, t_dictionary);
302
138k
    check_dict_read(*op1);
303
138k
    check_dict_write(*op);
304
138k
    if (!imemory->gs_lib_ctx->dict_auto_expand &&
305
138k
        (dict_length(op) != 0 || dict_maxlength(op) < dict_length(op1))
306
138k
        )
307
0
        return_error(gs_error_rangecheck);
308
138k
    code = idict_copy(op1, op);
309
138k
    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
138k
    if (!level2_enabled)
317
138k
        r_copy_attrs(dict_access_ref(op), a_write, dict_access_ref(op1));
318
138k
    ref_assign(op1, op);
319
138k
    pop(1);
320
138k
    return 0;
321
138k
}
322
323
/* - currentdict <dict> */
324
static int
325
zcurrentdict(i_ctx_t *i_ctx_p)
326
5.16M
{
327
5.16M
    os_ptr op = osp;
328
329
5.16M
    push(1);
330
5.16M
    ref_assign(op, dsp);
331
5.16M
    return 0;
332
5.16M
}
333
334
/* - countdictstack <int> */
335
static int
336
zcountdictstack(i_ctx_t *i_ctx_p)
337
28.4k
{
338
28.4k
    os_ptr op = osp;
339
28.4k
    uint count = ref_stack_count(&d_stack);
340
341
28.4k
    push(1);
342
28.4k
    if (!level2_enabled)
343
0
        count--;   /* see dstack.h */
344
28.4k
    make_int(op, count);
345
28.4k
    return 0;
346
28.4k
}
347
348
/* <array> dictstack <subarray> */
349
static int
350
zdictstack(i_ctx_t *i_ctx_p)
351
28.3k
{
352
28.3k
    os_ptr op = osp;
353
28.3k
    uint count = ref_stack_count(&d_stack);
354
355
28.3k
    check_op(1);
356
28.3k
    if (!level2_enabled)
357
0
        count--;   /* see dstack.h */
358
28.3k
    if (!r_is_array(op))
359
28.3k
        return_op_typecheck(op);
360
28.3k
    if (r_size(op) < count)
361
0
        return_error(gs_error_rangecheck);
362
28.3k
    if (!r_has_type_attrs(op, t_array, a_write))
363
0
        return_error(gs_error_invalidaccess);
364
28.3k
    return ref_stack_store(&d_stack, op, count, 0, 0, true, idmemory,
365
28.3k
                           "dictstack");
366
28.3k
}
367
368
/* - cleardictstack - */
369
static int
370
zcleardictstack(i_ctx_t *i_ctx_p)
371
99
{
372
103
    while (zend(i_ctx_p) >= 0)
373
99
        DO_NOTHING;
374
99
    return 0;
375
99
}
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
2.88M
{
384
2.88M
    uint count2 = ref_stack_counttomark(&o_stack);
385
2.88M
    ref rdict;
386
2.88M
    int code;
387
2.88M
    uint idx;
388
389
2.88M
    if (count2 == 0)
390
3
        return_error(gs_error_unmatchedmark);
391
2.88M
    count2--;
392
2.88M
    if ((count2 & 1) != 0)
393
1
        return_error(gs_error_rangecheck);
394
2.88M
    code = dict_create(count2 >> 1, &rdict);
395
2.88M
    if (code < 0)
396
0
        return code;
397
2.88M
    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
2.88M
    else {
408
       /* << /a 1 /a 2 >> => << /a 1 >>, i.e., */
409
       /* we must enter the keys in top-to-bottom order. */
410
93.9M
       for (idx = 0; idx < count2; idx += 2) {
411
91.1M
           code = idict_put(&rdict,
412
91.1M
                            ref_stack_index(&o_stack, idx + 1),
413
91.1M
                            ref_stack_index(&o_stack, idx));
414
91.1M
           if (code < 0) {         /* There's no way to free the dictionary -- too bad. */
415
0
               return code;
416
0
           }
417
91.1M
       }
418
2.88M
    }
419
2.88M
    ref_stack_pop(&o_stack, count2);
420
2.88M
    ref_assign(osp, &rdict);
421
2.88M
    return code;
422
2.88M
}
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
15.5k
{
434
15.5k
    os_ptr op = osp;
435
15.5k
    os_ptr op1 = op - 1;
436
15.5k
    int code;
437
438
15.5k
    check_op(2);
439
15.5k
    check_type(*op1, t_dictionary);
440
15.5k
    check_dict_read(*op1);
441
15.5k
    check_type(*op, t_dictionary);
442
    /*check_dict_write(*op);*/  /* see above */
443
    /* This is only recognized in Level 2 mode. */
444
15.5k
    if (!imemory->gs_lib_ctx->dict_auto_expand)
445
0
        return_error(gs_error_undefined);
446
15.5k
    code = idict_copy_new(op1, op);
447
15.5k
    if (code < 0)
448
0
        return code;
449
15.5k
    ref_assign(op1, op);
450
15.5k
    pop(1);
451
15.5k
    return 0;
452
15.5k
}
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
4.91M
{
463
4.91M
    os_ptr op = osp;
464
465
4.91M
    check_op(2);
466
4.91M
    check_type(op[-1], t_dictionary);
467
    /* Don't check_dict_write */
468
4.91M
    idict_undef(op - 1, op); /* ignore undefined error */
469
4.91M
    pop(2);
470
4.91M
    return 0;
471
4.91M
}
472
473
/* <dict> <key> .knownget <value> true */
474
/* <dict> <key> .knownget false */
475
static int
476
zknownget(i_ctx_t *i_ctx_p)
477
43.8M
{
478
43.8M
    os_ptr op = osp;
479
43.8M
    register os_ptr op1 = op - 1;
480
43.8M
    ref *pvalue;
481
482
43.8M
    check_op(2);
483
43.8M
    check_type(*op1, t_dictionary);
484
43.8M
    check_dict_read(*op1);
485
43.8M
    if (dict_find(op1, op, &pvalue) <= 0) {
486
11.7M
        make_false(op1);
487
11.7M
        pop(1);
488
32.1M
    } else {
489
32.1M
        ref_assign(op1, pvalue);
490
32.1M
        make_true(op);
491
32.1M
    }
492
43.8M
    return 0;
493
43.8M
}
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
690k
{
516
690k
    os_ptr op = osp;
517
690k
    os_ptr op1 = op - 1;
518
690k
    uint new_size;
519
690k
    int code;
520
521
690k
    check_op(2);
522
690k
    check_type(*op1, t_dictionary);
523
690k
    check_dict_write(*op1);
524
690k
    check_type(*op, t_integer);
525
690k
    if (op->value.intval < 0)
526
0
        return_error(gs_error_rangecheck);
527
690k
    new_size = (uint) op->value.intval;
528
690k
    if (dict_length(op - 1) > new_size)
529
0
        return_error(gs_error_dictfull);
530
690k
    code = idict_resize(op - 1, new_size);
531
690k
    if (code >= 0)
532
690k
        pop(2);
533
690k
    return code;
534
690k
}
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
};