Coverage Report

Created: 2025-06-10 07:15

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