Coverage Report

Created: 2026-09-14 07:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/psi/zgeneric.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
/* Array/string/dictionary generic operators for PostScript */
18
#include "memory_.h"
19
#include "ghost.h"
20
#include "gsstruct.h"   /* for st_bytes */
21
#include "oper.h"
22
#include "dstack.h"   /* for systemdict */
23
#include "estack.h"   /* for forall */
24
#include "iddict.h"
25
#include "iname.h"
26
#include "ipacked.h"
27
#include "ivmspace.h"
28
#include "store.h"
29
30
/* This file implements copy, get, put, getinterval, putinterval, */
31
/* length, and forall, which apply generically to */
32
/* arrays, strings, and dictionaries.  (Copy also has a special */
33
/* meaning for copying the top N elements of the stack.) */
34
35
/* See the comment in opdef.h for an invariant which allows */
36
/* more efficient implementation of forall. */
37
38
/* Forward references */
39
static int zcopy_integer(i_ctx_t *);
40
static int zcopy_interval(i_ctx_t *);
41
static int copy_interval(i_ctx_t *, os_ptr, uint, os_ptr, client_name_t);
42
43
/* <various1> <various2> copy <various> */
44
/* <obj1> ... <objn> <int> copy <obj1> ... <objn> <obj1> ... <objn> */
45
/* Note that this implements copy for arrays and strings, */
46
/* but not for dictionaries (see zcopy_dict in zdict.c). */
47
int
48
zcopy(i_ctx_t *i_ctx_p)
49
810M
{
50
810M
    os_ptr op = osp;
51
810M
    int type;
52
810M
    check_op(1);
53
810M
    type = r_type(op);
54
810M
    if (type == t_integer)
55
766M
        return zcopy_integer(i_ctx_p);
56
43.9M
    check_op(2);
57
43.9M
    switch (type) {
58
19.5M
        case t_array:
59
41.8M
        case t_string:
60
41.8M
            return zcopy_interval(i_ctx_p);
61
2.06M
        case t_dictionary:
62
2.06M
            return zcopy_dict(i_ctx_p);
63
9
        default:
64
9
            return_op_typecheck(op);
65
43.9M
    }
66
43.9M
}
67
68
/* <obj1> ... <objn> <int> copy <obj1> ... <objn> <obj1> ... <objn> */
69
static int
70
zcopy_integer(i_ctx_t *i_ctx_p)
71
766M
{
72
766M
    os_ptr op = osp;
73
766M
    os_ptr op1 = op - 1;
74
766M
    int count, i;
75
766M
    int code;
76
77
766M
    if ((uint) op->value.intval > (uint)(op - osbot)) {
78
        /* There might be enough elements in other blocks. */
79
33
        check_type(*op, t_integer);
80
33
        if (op->value.intval >= (int)ref_stack_count(&o_stack))
81
8
            return_error(gs_error_stackunderflow);
82
25
        if (op->value.intval < 0)
83
25
            return_error(gs_error_rangecheck);
84
25
        check_int_ltu(*op, ref_stack_count(&o_stack));
85
0
        count = op->value.intval;
86
766M
    } else if (op1 + (count = op->value.intval) <= ostop) {
87
        /* Fast case. */
88
766M
        memcpy((char *)op, (char *)(op - count), count * sizeof(ref));
89
766M
        push(count - 1);
90
766M
        return 0;
91
766M
    }
92
    /* Do it the slow, general way. */
93
33
    code = ref_stack_push(&o_stack, count - 1);
94
33
    if (code < 0)
95
0
        return code;
96
159
    for (i = 0; i < count; i++) {
97
126
        ref *o = ref_stack_index(&o_stack, i);
98
126
        ref *o1 = ref_stack_index(&o_stack, i + count);
99
100
126
        if (o == NULL || o1 == NULL)
101
0
            return_error(gs_error_stackunderflow);
102
126
        *o = *o1;
103
126
    }
104
33
    return 0;
105
33
}
106
107
/* <array1> <array2> copy <subarray2> */
108
/* <string1> <string2> copy <substring2> */
109
static int
110
zcopy_interval(i_ctx_t *i_ctx_p)
111
41.8M
{
112
41.8M
    os_ptr op = osp;
113
41.8M
    os_ptr op1 = op - 1;
114
41.8M
    int code = copy_interval(i_ctx_p, op, 0, op1, "copy");
115
116
41.8M
    if (code < 0)
117
2
        return code;
118
41.8M
    r_set_size(op, r_size(op1));
119
41.8M
    *op1 = *op;
120
41.8M
    pop(1);
121
41.8M
    return 0;
122
41.8M
}
123
124
/* <array|dict|name|packedarray|string> length <int> */
125
static int
126
zlength(i_ctx_t *i_ctx_p)
127
442M
{
128
442M
    os_ptr op = osp;
129
130
442M
    check_op(1);
131
442M
    switch (r_type(op)) {
132
45.4M
        case t_array:
133
328M
        case t_string:
134
329M
        case t_mixedarray:
135
331M
        case t_shortarray:
136
331M
            check_read(*op);
137
331M
            make_int(op, r_size(op));
138
331M
            return 0;
139
108M
        case t_dictionary:
140
108M
            check_dict_read(*op);
141
108M
            make_int(op, dict_length(op));
142
108M
            return 0;
143
1.62M
        case t_name: {
144
1.62M
            ref str;
145
146
1.62M
            name_string_ref(imemory, op, &str);
147
1.62M
            make_int(op, r_size(&str));
148
1.62M
            return 0;
149
108M
        }
150
2
        case t_astruct:
151
2
            if (gs_object_type(imemory, op->value.pstruct) != &st_bytes)
152
2
                return_error(gs_error_typecheck);
153
0
            check_read(*op);
154
0
            make_int(op, gs_object_size(imemory, op->value.pstruct));
155
0
            return 0;
156
11
        default:
157
11
            return_op_typecheck(op);
158
442M
    }
159
442M
}
160
161
/* <array|packedarray|string> <index> get <obj> */
162
/* <dict> <key> get <obj> */
163
static int
164
zget(i_ctx_t *i_ctx_p)
165
1.68G
{
166
1.68G
    int code;
167
1.68G
    os_ptr op = osp;
168
1.68G
    os_ptr op1 = op - 1;
169
1.68G
    ref *pvalue;
170
171
1.68G
    check_op(2);
172
173
1.68G
    switch (r_type(op1)) {
174
349M
        case t_dictionary:
175
349M
            check_dict_read(*op1);
176
349M
            if (dict_find(op1, op, &pvalue) <= 0)
177
22
                return_error(gs_error_undefined);
178
349M
            op[-1] = *pvalue;
179
349M
            break;
180
389M
        case t_string:
181
389M
            check_read(*op1);
182
389M
            check_int_ltu(*op, r_size(op1));
183
389M
            make_int(op1, op1->value.bytes[(uint) op->value.intval]);
184
389M
            break;
185
864M
        case t_array:
186
904M
        case t_mixedarray:
187
942M
        case t_shortarray:
188
942M
            check_type(*op, t_integer);
189
942M
            check_read(*op1);
190
942M
            code = array_get(imemory, op1, op->value.intval, op1);
191
942M
            if (code < 0)
192
3
                return code;
193
942M
            break;
194
942M
        case t__invalid:
195
0
            return_error(gs_error_stackunderflow);
196
16
        default:
197
16
            return_error(gs_error_typecheck);
198
1.68G
    }
199
1.68G
    pop(1);
200
1.68G
    return 0;
201
1.68G
}
202
203
/* <array> <index> <obj> put - */
204
/* <dict> <key> <value> put - */
205
/* <string> <index> <int> put - */
206
static int
207
zput(i_ctx_t *i_ctx_p)
208
1.02G
{
209
1.02G
    os_ptr op = osp;
210
1.02G
    os_ptr op1 = op - 1;
211
1.02G
    os_ptr op2 = op1 - 1;
212
1.02G
    byte *sdata;
213
1.02G
    uint ssize;
214
215
1.02G
    check_op(3);
216
1.02G
    switch (r_type(op2)) {
217
785M
        case t_dictionary:
218
785M
            check_dict_write(*op2);
219
785M
            {
220
785M
                int code = idict_put(op2, op1, op);
221
222
785M
                if (code < 0)
223
0
                    return code; /* error */
224
785M
            }
225
785M
            break;
226
785M
        case t_array:
227
71.2M
            check_write(*op2);
228
71.2M
            check_int_ltu(*op1, r_size(op2));
229
71.2M
            store_check_dest(op2, op);
230
71.2M
            {
231
71.2M
                ref *eltp = op2->value.refs + (uint) op1->value.intval;
232
233
71.2M
                ref_assign_old(op2, eltp, op, "put");
234
71.2M
            }
235
71.2M
            break;
236
0
        case t_mixedarray:  /* packed arrays are read-only */
237
0
        case t_shortarray:
238
0
            return_error(gs_error_invalidaccess);
239
164M
        case t_string:
240
164M
            sdata = op2->value.bytes;
241
164M
            ssize = r_size(op2);
242
164M
str:      check_write(*op2);
243
164M
            check_int_ltu(*op1, ssize);
244
164M
            check_int_leu(*op, 0xff);
245
164M
            sdata[(uint)op1->value.intval] = (byte)op->value.intval;
246
164M
            break;
247
0
        case t_astruct:
248
0
            if (gs_object_type(imemory, op2->value.pstruct) != &st_bytes)
249
0
                return_error(gs_error_typecheck);
250
0
            sdata = r_ptr(op2, byte);
251
0
            ssize = gs_object_size(imemory, op2->value.pstruct);
252
0
            goto str;
253
10
        default:
254
10
            return_op_typecheck(op2);
255
1.02G
    }
256
1.02G
    pop(3);
257
1.02G
    return 0;
258
1.02G
}
259
260
/* <array> <index> <obj> .forceput - */
261
/* <dict> <key> <value> .forceput - */
262
/*
263
 * This forces a "put" even if the object is not writable, and (if the
264
 * object is systemdict or the save level is 0) even if the value is in
265
 * local VM.  It is meant to be used only for replacing the value of
266
 * FontDirectory in systemdict when switching between local and global VM,
267
 * and a few similar applications.  After initialization, this operator
268
 * should no longer be accessible by name.
269
 */
270
static int
271
zforceput(i_ctx_t *i_ctx_p)
272
59.2M
{
273
59.2M
    os_ptr op = osp;
274
59.2M
    os_ptr op1 = op - 1;
275
59.2M
    os_ptr op2 = op - 2;
276
59.2M
    int code;
277
278
59.2M
    check_op(3);
279
280
59.2M
    switch (r_type(op2)) {
281
0
    case t_array:
282
0
        check_int_ltu(*op1, r_size(op2));
283
0
        if (r_space(op2) > r_space(op)) {
284
0
            if (imemory_save_level(iimemory))
285
0
                return_error(gs_error_invalidaccess);
286
0
        }
287
0
        {
288
0
            ref *eltp = op2->value.refs + (uint) op1->value.intval;
289
290
0
            ref_assign_old(op2, eltp, op, "put");
291
0
        }
292
0
        break;
293
59.2M
    case t_dictionary:
294
59.2M
        if (op2->value.pdict == systemdict->value.pdict ||
295
635k
            !imemory_save_level(iimemory)
296
59.2M
            ) {
297
59.1M
            uint space = r_space(op2);
298
299
59.1M
            r_set_space(op2, avm_local);
300
59.1M
            code = idict_put(op2, op1, op);
301
59.1M
            r_set_space(op2, space);
302
59.1M
        } else
303
193k
            code = idict_put(op2, op1, op);
304
59.2M
        if (code < 0)
305
5
            return code;
306
59.2M
        break;
307
59.2M
    default:
308
0
        return_error(gs_error_typecheck);
309
59.2M
    }
310
59.2M
    pop(3);
311
59.2M
    return 0;
312
59.2M
}
313
314
/* <seq:array|packedarray|string> <index> <count> getinterval <subseq> */
315
static int
316
zgetinterval(i_ctx_t *i_ctx_p)
317
59.7M
{
318
59.7M
    os_ptr op = osp;
319
59.7M
    os_ptr op1 = op - 1;
320
59.7M
    os_ptr op2 = op1 - 1;
321
59.7M
    uint index;
322
59.7M
    uint count;
323
324
59.7M
    check_op(3);
325
326
59.7M
    switch (r_type(op2)) {
327
3
        default:
328
3
            return_op_typecheck(op2);
329
3.59M
        case t_array:
330
36.9M
        case t_string:
331
59.7M
        case t_mixedarray:
332
59.7M
        case t_shortarray:;
333
59.7M
    }
334
59.7M
    check_read(*op2);
335
59.7M
    check_int_leu(*op1, r_size(op2));
336
59.7M
    index = op1->value.intval;
337
59.7M
    check_int_leu(*op, r_size(op2) - index);
338
59.7M
    count = op->value.intval;
339
59.7M
    switch (r_type(op2)) {
340
3.59M
        case t_array:
341
3.59M
            op2->value.refs += index;
342
3.59M
            break;
343
33.3M
        case t_string:
344
33.3M
            op2->value.bytes += index;
345
33.3M
            break;
346
22.7M
        case t_mixedarray: {
347
22.7M
            const ref_packed *packed = op2->value.packed;
348
349
180M
            for (; index--;)
350
157M
                packed = packed_next(packed);
351
22.7M
            op2->value.packed = packed;
352
22.7M
            break;
353
0
        }
354
0
        case t_shortarray:
355
0
            op2->value.packed += index;
356
0
            break;
357
59.7M
    }
358
59.7M
    r_set_size(op2, count);
359
59.7M
    pop(2);
360
59.7M
    return 0;
361
59.7M
}
362
363
/* <array1> <index> <array2|packedarray2> putinterval - */
364
/* <string1> <index> <string2> putinterval - */
365
/* <bytestring1> <index> <string2> putinterval - */
366
static int
367
zputinterval(i_ctx_t *i_ctx_p)
368
18.1M
{
369
18.1M
    os_ptr op = osp;
370
18.1M
    os_ptr opindex = op - 1;
371
18.1M
    os_ptr opto = opindex - 1;
372
18.1M
    int code;
373
374
18.1M
    check_op(3);
375
376
18.1M
    switch (r_type(opto)) {
377
5
        default:
378
5
            return_error(gs_error_typecheck);
379
0
        case t__invalid:
380
0
            if (r_type(op) != t_array && r_type(op) != t_string && r_type(op) != t__invalid)
381
0
                return_error(gs_error_typecheck); /* to match Distiller */
382
0
            else
383
0
                return_error(gs_error_stackunderflow);
384
0
        case t_mixedarray:
385
0
        case t_shortarray:
386
0
            return_error(gs_error_invalidaccess);
387
2.35M
        case t_array:
388
18.1M
        case t_string:
389
18.1M
            check_write(*opto);
390
18.1M
            check_int_leu(*opindex, r_size(opto));
391
18.1M
            code = copy_interval(i_ctx_p, opto, (uint)(opindex->value.intval),
392
18.1M
                                 op, "putinterval");
393
18.1M
            break;
394
0
        case t_astruct: {
395
0
            uint dsize, ssize, index;
396
397
0
            check_write(*opto);
398
0
            if (gs_object_type(imemory, opto->value.pstruct) != &st_bytes)
399
0
                return_error(gs_error_typecheck);
400
0
            dsize = gs_object_size(imemory, opto->value.pstruct);
401
0
            check_int_leu(*opindex, dsize);
402
0
            index = (uint)opindex->value.intval;
403
0
            check_read_type(*op, t_string);
404
0
            ssize = r_size(op);
405
0
            if (ssize > dsize - index)
406
0
                return_error(gs_error_rangecheck);
407
0
            memcpy(r_ptr(opto, byte) + index, op->value.const_bytes, ssize);
408
0
            code = 0;
409
0
            break;
410
0
        }
411
18.1M
    }
412
18.1M
    if (code >= 0)
413
18.1M
        pop(3);
414
18.1M
    return code;
415
18.1M
}
416
417
/*  <dict> <name> <string> .putgstringcopy - */
418
static int
419
zputgstringcopy(i_ctx_t *i_ctx_p)
420
9.66k
{
421
9.66k
    os_ptr op = osp;
422
9.66k
    byte *sbody;
423
9.66k
    uint size;
424
9.66k
    int code;
425
9.66k
    avm_space cs = ialloc_space(idmemory);
426
9.66k
    avm_space ds = r_space((op - 2));
427
9.66k
    avm_space ss = r_space(op);
428
429
    /* first, check our operands */
430
9.66k
    check_op(3);
431
9.66k
    check_read_type(*op, t_string);
432
9.66k
    check_type(*(op - 1), t_name);
433
9.66k
    check_type(*(op - 2), t_dictionary);
434
435
    /* If the string and the dictionary differ in globalness... */
436
9.66k
    if (ss != ds) {
437
0
        size = r_size(op);
438
0
        ialloc_set_space(idmemory, ds);
439
440
0
        sbody = ialloc_string(size, "string");
441
0
        if (sbody == 0) {
442
0
            ialloc_set_space(idmemory, cs);
443
0
            return_error(gs_error_VMerror);
444
0
        }
445
0
        memcpy(sbody, op->value.bytes, size);
446
0
        make_string(op, a_all | icurrent_space, size, sbody);
447
0
    }
448
    /* use dict_put() directly here, because we want to return
449
       the VM space back before we return in the event of an error
450
     */
451
9.66k
    code = dict_put(op - 2, op - 1, op, &(i_ctx_p->dict_stack));
452
453
    /* put the space back how it was */
454
9.66k
    if (ss != ds)
455
0
        ialloc_set_space(idmemory, cs);
456
457
9.66k
    if (code < 0)
458
0
        return code;
459
460
9.66k
    pop(3);
461
9.66k
    return 0;
462
9.66k
}
463
464
/* <array|packedarray|string> <<element> proc> forall - */
465
/* <dict> <<key> <value> proc> forall - */
466
static int
467
    array_continue(i_ctx_t *),
468
    dict_continue(i_ctx_t *),
469
    string_continue(i_ctx_t *),
470
    packedarray_continue(i_ctx_t *);
471
static int forall_cleanup(i_ctx_t *);
472
static int
473
zforall(i_ctx_t *i_ctx_p)
474
51.3M
{
475
51.3M
    os_ptr op = osp;
476
51.3M
    os_ptr obj = op - 1;
477
51.3M
    es_ptr ep;
478
51.3M
    es_ptr cproc;
479
480
51.3M
    check_estack(6);
481
    /* check_estack() could cause the exec stack to be copied to a new block
482
     * so don't caulculate ep and things based on ep until *after* the check
483
     */
484
51.3M
    ep = esp;
485
51.3M
    cproc = ep + 4;
486
51.3M
    check_proc(*op);
487
51.3M
    switch (r_type(obj)) {
488
12
        default:
489
12
            return_op_typecheck(obj);
490
15.3M
        case t_array:
491
15.3M
            check_read(*obj);
492
15.3M
            make_op_estack(cproc, array_continue);
493
15.3M
            break;
494
27.1M
        case t_dictionary:
495
27.1M
            check_dict_read(*obj);
496
27.1M
            make_int(cproc, dict_first(obj));
497
27.1M
            ++cproc;
498
27.1M
            make_op_estack(cproc, dict_continue);
499
27.1M
            break;
500
146k
        case t_string:
501
146k
            check_read(*obj);
502
146k
            make_op_estack(cproc, string_continue);
503
146k
            break;
504
6.65M
        case t_mixedarray:
505
8.70M
        case t_shortarray:
506
8.70M
            check_read(*obj);
507
8.70M
            make_op_estack(cproc, packedarray_continue);
508
8.70M
            break;
509
51.3M
    }
510
    /*
511
     * Push:
512
     *   - a mark;
513
     *   - the composite object;
514
     *   - the procedure;
515
     *   - the iteration index (only for dictionaries, done above);
516
     * and invoke the continuation operator.
517
     */
518
51.3M
    make_mark_estack(ep + 1, es_for, forall_cleanup);
519
51.3M
    ep[2] = *obj;
520
51.3M
    ep[3] = *op;
521
51.3M
    esp = cproc - 1;
522
51.3M
    ref_stack_pop(&o_stack, 2);
523
51.3M
    return (*real_opproc(cproc))(i_ctx_p);
524
51.3M
}
525
/* Continuation operator for arrays */
526
static int
527
array_continue(i_ctx_t *i_ctx_p)
528
171M
{
529
171M
    os_ptr op = osp;
530
171M
    es_ptr obj = esp - 1;
531
532
171M
    if (r_size(obj)) {   /* continue */
533
156M
        push(1);
534
156M
        r_dec_size(obj, 1);
535
156M
        *op = *obj->value.refs;
536
156M
        obj->value.refs++;
537
156M
        esp += 2;
538
156M
        *esp = obj[1];
539
156M
        return o_push_estack;
540
156M
    } else {     /* done */
541
15.1M
        esp -= 3;    /* pop mark, object, proc */
542
15.1M
        return o_pop_estack;
543
15.1M
    }
544
171M
}
545
/* Continuation operator for dictionaries */
546
static int
547
dict_continue(i_ctx_t *i_ctx_p)
548
1.30G
{
549
1.30G
    os_ptr op = osp;
550
1.30G
    es_ptr obj = esp - 2;
551
1.30G
    int index = esp->value.intval;
552
553
1.30G
    if (r_type(obj) != t_dictionary)
554
0
        return_error(gs_error_typecheck);
555
556
1.30G
    push(2);     /* make room for key and value */
557
1.30G
    if ((index = dict_next(obj, index, op - 1)) >= 0) { /* continue */
558
1.27G
        esp->value.intval = index;
559
1.27G
        esp += 2;
560
1.27G
        *esp = obj[1];
561
1.27G
        return o_push_estack;
562
1.27G
    } else {     /* done */
563
26.7M
        pop(2);      /* undo push */
564
26.7M
        esp -= 4;    /* pop mark, object, proc, index */
565
26.7M
        return o_pop_estack;
566
26.7M
    }
567
1.30G
}
568
/* Continuation operator for strings */
569
static int
570
string_continue(i_ctx_t *i_ctx_p)
571
147k
{
572
147k
    os_ptr op = osp;
573
147k
    es_ptr obj = esp - 1;
574
575
147k
    if (r_size(obj)) {   /* continue */
576
120
        push(1);    /* check for result space on stack BEFORE changing string size */
577
120
        r_dec_size(obj, 1); /* Bug 701550 :-O */
578
120
        make_int(op, *obj->value.bytes);
579
120
        obj->value.bytes++;
580
120
        esp += 2;
581
120
        *esp = obj[1];
582
120
        return o_push_estack;
583
146k
    } else {     /* done */
584
146k
        esp -= 3;    /* pop mark, object, proc */
585
146k
        return o_pop_estack;
586
146k
    }
587
147k
}
588
/* Continuation operator for packed arrays */
589
static int
590
packedarray_continue(i_ctx_t *i_ctx_p)
591
44.6M
{
592
44.6M
    os_ptr op = osp;
593
44.6M
    es_ptr obj = esp - 1;
594
595
44.6M
    if (r_size(obj)) {   /* continue */
596
35.9M
        const ref_packed *packed = obj->value.packed;
597
598
35.9M
        push(1);
599
35.9M
        r_dec_size(obj, 1);
600
35.9M
        packed_get(imemory, packed, op);
601
35.9M
        obj->value.packed = packed_next(packed);
602
35.9M
        esp += 2;
603
35.9M
        *esp = obj[1];
604
35.9M
        return o_push_estack;
605
35.9M
    } else {     /* done */
606
8.70M
        esp -= 3;    /* pop mark, object, proc */
607
8.70M
        return o_pop_estack;
608
8.70M
    }
609
44.6M
}
610
/* Vacuous cleanup procedure */
611
static int
612
forall_cleanup(i_ctx_t *i_ctx_p)
613
599k
{
614
599k
    return 0;
615
599k
}
616
617
/* ------ Initialization procedure ------ */
618
619
const op_def zgeneric_op_defs[] =
620
{
621
    {"1copy", zcopy},
622
    {"2forall", zforall},
623
    {"3.forceput", zforceput},
624
    {"2get", zget},
625
    {"3getinterval", zgetinterval},
626
    {"1length", zlength},
627
    {"3put", zput},
628
    {"3putinterval", zputinterval},
629
    {"3.putgstringcopy", zputgstringcopy},
630
                /* Internal operators */
631
    {"0%array_continue", array_continue},
632
    {"0%dict_continue", dict_continue},
633
    {"0%packedarray_continue", packedarray_continue},
634
    {"0%string_continue", string_continue},
635
    op_def_end(0)
636
};
637
638
/* ------ Shared routines ------ */
639
640
/* Copy an interval from one operand to another. */
641
/* This is used by both putinterval and string/array copy. */
642
/* The destination is known to be an array or string, */
643
/* and the starting index is known to be less than or equal to */
644
/* its length; nothing else has been checked. */
645
static int
646
copy_interval(i_ctx_t *i_ctx_p /* for ref_assign_old */, os_ptr prto,
647
              uint index, os_ptr prfrom, client_name_t cname)
648
59.9M
{
649
59.9M
    int fromtype = r_type(prfrom);
650
59.9M
    uint fromsize = r_size(prfrom);
651
652
59.9M
    if (!(fromtype == r_type(prto) ||
653
147k
          ((fromtype == t_shortarray || fromtype == t_mixedarray) &&
654
147k
           r_type(prto) == t_array))
655
59.9M
        )
656
59.9M
        return_op_typecheck(prfrom);
657
59.9M
    check_read(*prfrom);
658
59.9M
    check_write(*prto);
659
59.9M
    if (fromsize > r_size(prto) - index)
660
0
        return_error(gs_error_rangecheck);
661
59.9M
    switch (fromtype) {
662
21.7M
        case t_array:
663
21.7M
            {     /* We have to worry about aliasing, */
664
                /* but refcpy_to_old takes care of it for us. */
665
21.7M
                return refcpy_to_old(prto, index, prfrom->value.refs,
666
21.7M
                                     fromsize, idmemory, cname);
667
0
            }
668
38.0M
        case t_string:
669
38.0M
            { /* memmove takes care of aliasing. */
670
38.0M
                memmove(prto->value.bytes + index, prfrom->value.bytes,
671
38.0M
                        fromsize);
672
38.0M
            }
673
38.0M
            break;
674
147k
        case t_mixedarray:
675
147k
        case t_shortarray:
676
147k
            { /* We don't have to worry about aliasing, because */
677
                /* packed arrays are read-only and hence the destination */
678
                /* can't be a packed array. */
679
147k
                uint i;
680
147k
                const ref_packed *packed = prfrom->value.packed;
681
147k
                ref *pdest = prto->value.refs + index;
682
147k
                ref elt;
683
684
37.8M
                for (i = 0; i < fromsize; i++, pdest++) {
685
37.7M
                    packed_get(imemory, packed, &elt);
686
37.7M
                    ref_assign_old(prto, pdest, &elt, cname);
687
37.7M
                    packed = packed_next(packed);
688
37.7M
                }
689
147k
            }
690
147k
            break;
691
59.9M
    }
692
38.1M
    return 0;
693
59.9M
}