Coverage Report

Created: 2025-06-10 07:24

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