Coverage Report

Created: 2025-06-10 07:24

/src/ghostpdl/psi/zgeneric.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
/* 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
53.6M
{
50
53.6M
    os_ptr op = osp;
51
53.6M
    int type;
52
53.6M
    check_op(1);
53
53.6M
    type = r_type(op);
54
53.6M
    if (type == t_integer)
55
50.8M
        return zcopy_integer(i_ctx_p);
56
2.85M
    check_op(2);
57
2.85M
    switch (type) {
58
1.30M
        case t_array:
59
2.71M
        case t_string:
60
2.71M
            return zcopy_interval(i_ctx_p);
61
136k
        case t_dictionary:
62
136k
            return zcopy_dict(i_ctx_p);
63
0
        default:
64
0
            return_op_typecheck(op);
65
2.85M
    }
66
2.85M
}
67
68
/* <obj1> ... <objn> <int> copy <obj1> ... <objn> <obj1> ... <objn> */
69
static int
70
zcopy_integer(i_ctx_t *i_ctx_p)
71
50.8M
{
72
50.8M
    os_ptr op = osp;
73
50.8M
    os_ptr op1 = op - 1;
74
50.8M
    int count, i;
75
50.8M
    int code;
76
77
50.8M
    if ((uint) op->value.intval > (uint)(op - osbot)) {
78
        /* There might be enough elements in other blocks. */
79
2
        check_type(*op, t_integer);
80
2
        if (op->value.intval >= (int)ref_stack_count(&o_stack))
81
0
            return_error(gs_error_stackunderflow);
82
2
        if (op->value.intval < 0)
83
2
            return_error(gs_error_rangecheck);
84
2
        check_int_ltu(*op, ref_stack_count(&o_stack));
85
0
        count = op->value.intval;
86
50.8M
    } else if (op1 + (count = op->value.intval) <= ostop) {
87
        /* Fast case. */
88
50.8M
        memcpy((char *)op, (char *)(op - count), count * sizeof(ref));
89
50.8M
        push(count - 1);
90
50.8M
        return 0;
91
50.8M
    }
92
    /* Do it the slow, general way. */
93
1
    code = ref_stack_push(&o_stack, count - 1);
94
1
    if (code < 0)
95
0
        return code;
96
5
    for (i = 0; i < count; i++) {
97
4
        ref *o = ref_stack_index(&o_stack, i);
98
4
        ref *o1 = ref_stack_index(&o_stack, i + count);
99
100
4
        if (o == NULL || o1 == NULL)
101
0
            return_error(gs_error_stackunderflow);
102
4
        *o = *o1;
103
4
    }
104
1
    return 0;
105
1
}
106
107
/* <array1> <array2> copy <subarray2> */
108
/* <string1> <string2> copy <substring2> */
109
static int
110
zcopy_interval(i_ctx_t *i_ctx_p)
111
2.71M
{
112
2.71M
    os_ptr op = osp;
113
2.71M
    os_ptr op1 = op - 1;
114
2.71M
    int code = copy_interval(i_ctx_p, op, 0, op1, "copy");
115
116
2.71M
    if (code < 0)
117
0
        return code;
118
2.71M
    r_set_size(op, r_size(op1));
119
2.71M
    *op1 = *op;
120
2.71M
    pop(1);
121
2.71M
    return 0;
122
2.71M
}
123
124
/* <array|dict|name|packedarray|string> length <int> */
125
static int
126
zlength(i_ctx_t *i_ctx_p)
127
29.7M
{
128
29.7M
    os_ptr op = osp;
129
130
29.7M
    check_op(1);
131
29.7M
    switch (r_type(op)) {
132
3.16M
        case t_array:
133
21.9M
        case t_string:
134
22.0M
        case t_mixedarray:
135
22.2M
        case t_shortarray:
136
22.2M
            check_read(*op);
137
22.2M
            make_int(op, r_size(op));
138
22.2M
            return 0;
139
7.39M
        case t_dictionary:
140
7.39M
            check_dict_read(*op);
141
7.39M
            make_int(op, dict_length(op));
142
7.39M
            return 0;
143
92.1k
        case t_name: {
144
92.1k
            ref str;
145
146
92.1k
            name_string_ref(imemory, op, &str);
147
92.1k
            make_int(op, r_size(&str));
148
92.1k
            return 0;
149
7.39M
        }
150
0
        case t_astruct:
151
0
            if (gs_object_type(imemory, op->value.pstruct) != &st_bytes)
152
0
                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
1
        default:
157
1
            return_op_typecheck(op);
158
29.7M
    }
159
29.7M
}
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
110M
{
166
110M
    int code;
167
110M
    os_ptr op = osp;
168
110M
    os_ptr op1 = op - 1;
169
110M
    ref *pvalue;
170
171
110M
    check_op(2);
172
173
110M
    switch (r_type(op1)) {
174
22.6M
        case t_dictionary:
175
22.6M
            check_dict_read(*op1);
176
22.6M
            if (dict_find(op1, op, &pvalue) <= 0)
177
0
                return_error(gs_error_undefined);
178
22.6M
            op[-1] = *pvalue;
179
22.6M
            break;
180
25.8M
        case t_string:
181
25.8M
            check_read(*op1);
182
25.8M
            check_int_ltu(*op, r_size(op1));
183
25.8M
            make_int(op1, op1->value.bytes[(uint) op->value.intval]);
184
25.8M
            break;
185
57.1M
        case t_array:
186
59.7M
        case t_mixedarray:
187
62.3M
        case t_shortarray:
188
62.3M
            check_type(*op, t_integer);
189
62.3M
            check_read(*op1);
190
62.3M
            code = array_get(imemory, op1, op->value.intval, op1);
191
62.3M
            if (code < 0)
192
1
                return code;
193
62.3M
            break;
194
62.3M
        case t__invalid:
195
0
            return_error(gs_error_stackunderflow);
196
0
        default:
197
0
            return_error(gs_error_typecheck);
198
110M
    }
199
110M
    pop(1);
200
110M
    return 0;
201
110M
}
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
99.7M
{
209
99.7M
    os_ptr op = osp;
210
99.7M
    os_ptr op1 = op - 1;
211
99.7M
    os_ptr op2 = op1 - 1;
212
99.7M
    byte *sdata;
213
99.7M
    uint ssize;
214
215
99.7M
    check_op(3);
216
99.7M
    switch (r_type(op2)) {
217
83.7M
        case t_dictionary:
218
83.7M
            check_dict_write(*op2);
219
83.7M
            {
220
83.7M
                int code = idict_put(op2, op1, op);
221
222
83.7M
                if (code < 0)
223
0
                    return code; /* error */
224
83.7M
            }
225
83.7M
            break;
226
83.7M
        case t_array:
227
4.71M
            check_write(*op2);
228
4.71M
            check_int_ltu(*op1, r_size(op2));
229
4.71M
            store_check_dest(op2, op);
230
4.71M
            {
231
4.71M
                ref *eltp = op2->value.refs + (uint) op1->value.intval;
232
233
4.71M
                ref_assign_old(op2, eltp, op, "put");
234
4.71M
            }
235
4.71M
            break;
236
0
        case t_mixedarray:  /* packed arrays are read-only */
237
0
        case t_shortarray:
238
0
            return_error(gs_error_invalidaccess);
239
11.2M
        case t_string:
240
11.2M
            sdata = op2->value.bytes;
241
11.2M
            ssize = r_size(op2);
242
11.2M
str:      check_write(*op2);
243
11.2M
            check_int_ltu(*op1, ssize);
244
11.2M
            check_int_leu(*op, 0xff);
245
11.2M
            sdata[(uint)op1->value.intval] = (byte)op->value.intval;
246
11.2M
            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
1
        default:
254
1
            return_op_typecheck(op2);
255
99.7M
    }
256
99.7M
    pop(3);
257
99.7M
    return 0;
258
99.7M
}
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
4.54M
{
273
4.54M
    os_ptr op = osp;
274
4.54M
    os_ptr op1 = op - 1;
275
4.54M
    os_ptr op2 = op - 2;
276
4.54M
    int code;
277
278
4.54M
    check_op(3);
279
280
4.54M
    switch (r_type(op2)) {
281
9.78k
    case t_array:
282
9.78k
        check_int_ltu(*op1, r_size(op2));
283
9.78k
        if (r_space(op2) > r_space(op)) {
284
0
            if (imemory_save_level(iimemory))
285
0
                return_error(gs_error_invalidaccess);
286
0
        }
287
9.78k
        {
288
9.78k
            ref *eltp = op2->value.refs + (uint) op1->value.intval;
289
290
9.78k
            ref_assign_old(op2, eltp, op, "put");
291
9.78k
        }
292
9.78k
        break;
293
4.53M
    case t_dictionary:
294
4.53M
        if (op2->value.pdict == systemdict->value.pdict ||
295
4.53M
            !imemory_save_level(iimemory)
296
4.53M
            ) {
297
4.42M
            uint space = r_space(op2);
298
299
4.42M
            r_set_space(op2, avm_local);
300
4.42M
            code = idict_put(op2, op1, op);
301
4.42M
            r_set_space(op2, space);
302
4.42M
        } else
303
112k
            code = idict_put(op2, op1, op);
304
4.53M
        if (code < 0)
305
0
            return code;
306
4.53M
        break;
307
4.53M
    default:
308
0
        return_error(gs_error_typecheck);
309
4.54M
    }
310
4.54M
    pop(3);
311
4.54M
    return 0;
312
4.54M
}
313
314
/* <seq:array|packedarray|string> <index> <count> getinterval <subseq> */
315
static int
316
zgetinterval(i_ctx_t *i_ctx_p)
317
3.98M
{
318
3.98M
    os_ptr op = osp;
319
3.98M
    os_ptr op1 = op - 1;
320
3.98M
    os_ptr op2 = op1 - 1;
321
3.98M
    uint index;
322
3.98M
    uint count;
323
324
3.98M
    check_op(3);
325
326
3.98M
    switch (r_type(op2)) {
327
0
        default:
328
0
            return_op_typecheck(op2);
329
237k
        case t_array:
330
2.48M
        case t_string:
331
3.98M
        case t_mixedarray:
332
3.98M
        case t_shortarray:;
333
3.98M
    }
334
3.98M
    check_read(*op2);
335
3.98M
    check_int_leu(*op1, r_size(op2));
336
3.98M
    index = op1->value.intval;
337
3.98M
    check_int_leu(*op, r_size(op2) - index);
338
3.98M
    count = op->value.intval;
339
3.98M
    switch (r_type(op2)) {
340
237k
        case t_array:
341
237k
            op2->value.refs += index;
342
237k
            break;
343
2.24M
        case t_string:
344
2.24M
            op2->value.bytes += index;
345
2.24M
            break;
346
1.50M
        case t_mixedarray: {
347
1.50M
            const ref_packed *packed = op2->value.packed;
348
349
11.9M
            for (; index--;)
350
10.4M
                packed = packed_next(packed);
351
1.50M
            op2->value.packed = packed;
352
1.50M
            break;
353
0
        }
354
0
        case t_shortarray:
355
0
            op2->value.packed += index;
356
0
            break;
357
3.98M
    }
358
3.98M
    r_set_size(op2, count);
359
3.98M
    pop(2);
360
3.98M
    return 0;
361
3.98M
}
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
1.13M
{
369
1.13M
    os_ptr op = osp;
370
1.13M
    os_ptr opindex = op - 1;
371
1.13M
    os_ptr opto = opindex - 1;
372
1.13M
    int code;
373
374
1.13M
    check_op(3);
375
376
1.13M
    switch (r_type(opto)) {
377
0
        default:
378
0
            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
198k
        case t_array:
388
1.13M
        case t_string:
389
1.13M
            check_write(*opto);
390
1.13M
            check_int_leu(*opindex, r_size(opto));
391
1.13M
            code = copy_interval(i_ctx_p, opto, (uint)(opindex->value.intval),
392
1.13M
                                 op, "putinterval");
393
1.13M
            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
1.13M
    }
412
1.13M
    if (code >= 0)
413
1.13M
        pop(3);
414
1.13M
    return code;
415
1.13M
}
416
417
/* <array|packedarray|string> <<element> proc> forall - */
418
/* <dict> <<key> <value> proc> forall - */
419
static int
420
    array_continue(i_ctx_t *),
421
    dict_continue(i_ctx_t *),
422
    string_continue(i_ctx_t *),
423
    packedarray_continue(i_ctx_t *);
424
static int forall_cleanup(i_ctx_t *);
425
static int
426
zforall(i_ctx_t *i_ctx_p)
427
4.16M
{
428
4.16M
    os_ptr op = osp;
429
4.16M
    os_ptr obj = op - 1;
430
4.16M
    es_ptr ep;
431
4.16M
    es_ptr cproc;
432
433
4.16M
    check_estack(6);
434
    /* check_estack() could cause the exec stack to be copied to a new block
435
     * so don't caulculate ep and things based on ep until *after* the check
436
     */
437
4.16M
    ep = esp;
438
4.16M
    cproc = ep + 4;
439
4.16M
    check_proc(*op);
440
4.16M
    switch (r_type(obj)) {
441
2
        default:
442
2
            return_op_typecheck(obj);
443
1.18M
        case t_array:
444
1.18M
            check_read(*obj);
445
1.18M
            make_op_estack(cproc, array_continue);
446
1.18M
            break;
447
2.41M
        case t_dictionary:
448
2.41M
            check_dict_read(*obj);
449
2.41M
            make_int(cproc, dict_first(obj));
450
2.41M
            ++cproc;
451
2.41M
            make_op_estack(cproc, dict_continue);
452
2.41M
            break;
453
9.78k
        case t_string:
454
9.78k
            check_read(*obj);
455
9.78k
            make_op_estack(cproc, string_continue);
456
9.78k
            break;
457
440k
        case t_mixedarray:
458
557k
        case t_shortarray:
459
557k
            check_read(*obj);
460
557k
            make_op_estack(cproc, packedarray_continue);
461
557k
            break;
462
4.16M
    }
463
    /*
464
     * Push:
465
     *   - a mark;
466
     *   - the composite object;
467
     *   - the procedure;
468
     *   - the iteration index (only for dictionaries, done above);
469
     * and invoke the continuation operator.
470
     */
471
4.16M
    make_mark_estack(ep + 1, es_for, forall_cleanup);
472
4.16M
    ep[2] = *obj;
473
4.16M
    ep[3] = *op;
474
4.16M
    esp = cproc - 1;
475
4.16M
    ref_stack_pop(&o_stack, 2);
476
4.16M
    return (*real_opproc(cproc))(i_ctx_p);
477
4.16M
}
478
/* Continuation operator for arrays */
479
static int
480
array_continue(i_ctx_t *i_ctx_p)
481
12.5M
{
482
12.5M
    os_ptr op = osp;
483
12.5M
    es_ptr obj = esp - 1;
484
485
12.5M
    if (r_size(obj)) {   /* continue */
486
11.3M
        push(1);
487
11.3M
        r_dec_size(obj, 1);
488
11.3M
        *op = *obj->value.refs;
489
11.3M
        obj->value.refs++;
490
11.3M
        esp += 2;
491
11.3M
        *esp = obj[1];
492
11.3M
        return o_push_estack;
493
11.3M
    } else {     /* done */
494
1.17M
        esp -= 3;    /* pop mark, object, proc */
495
1.17M
        return o_pop_estack;
496
1.17M
    }
497
12.5M
}
498
/* Continuation operator for dictionaries */
499
static int
500
dict_continue(i_ctx_t *i_ctx_p)
501
145M
{
502
145M
    os_ptr op = osp;
503
145M
    es_ptr obj = esp - 2;
504
145M
    int index = esp->value.intval;
505
506
145M
    if (r_type(obj) != t_dictionary)
507
0
        return_error(gs_error_typecheck);
508
509
145M
    push(2);     /* make room for key and value */
510
145M
    if ((index = dict_next(obj, index, op - 1)) >= 0) { /* continue */
511
142M
        esp->value.intval = index;
512
142M
        esp += 2;
513
142M
        *esp = obj[1];
514
142M
        return o_push_estack;
515
142M
    } else {     /* done */
516
2.38M
        pop(2);      /* undo push */
517
2.38M
        esp -= 4;    /* pop mark, object, proc, index */
518
2.38M
        return o_pop_estack;
519
2.38M
    }
520
145M
}
521
/* Continuation operator for strings */
522
static int
523
string_continue(i_ctx_t *i_ctx_p)
524
9.78k
{
525
9.78k
    os_ptr op = osp;
526
9.78k
    es_ptr obj = esp - 1;
527
528
9.78k
    if (r_size(obj)) {   /* continue */
529
0
        push(1);    /* check for result space on stack BEFORE changing string size */
530
0
        r_dec_size(obj, 1); /* Bug 701550 :-O */
531
0
        make_int(op, *obj->value.bytes);
532
0
        obj->value.bytes++;
533
0
        esp += 2;
534
0
        *esp = obj[1];
535
0
        return o_push_estack;
536
9.78k
    } else {     /* done */
537
9.78k
        esp -= 3;    /* pop mark, object, proc */
538
9.78k
        return o_pop_estack;
539
9.78k
    }
540
9.78k
}
541
/* Continuation operator for packed arrays */
542
static int
543
packedarray_continue(i_ctx_t *i_ctx_p)
544
2.86M
{
545
2.86M
    os_ptr op = osp;
546
2.86M
    es_ptr obj = esp - 1;
547
548
2.86M
    if (r_size(obj)) {   /* continue */
549
2.30M
        const ref_packed *packed = obj->value.packed;
550
551
2.30M
        r_dec_size(obj, 1);
552
2.30M
        push(1);
553
2.30M
        packed_get(imemory, packed, op);
554
2.30M
        obj->value.packed = packed_next(packed);
555
2.30M
        esp += 2;
556
2.30M
        *esp = obj[1];
557
2.30M
        return o_push_estack;
558
2.30M
    } else {     /* done */
559
557k
        esp -= 3;    /* pop mark, object, proc */
560
557k
        return o_pop_estack;
561
557k
    }
562
2.86M
}
563
/* Vacuous cleanup procedure */
564
static int
565
forall_cleanup(i_ctx_t *i_ctx_p)
566
39.6k
{
567
39.6k
    return 0;
568
39.6k
}
569
570
/* ------ Initialization procedure ------ */
571
572
const op_def zgeneric_op_defs[] =
573
{
574
    {"1copy", zcopy},
575
    {"2forall", zforall},
576
    {"3.forceput", zforceput},
577
    {"2get", zget},
578
    {"3getinterval", zgetinterval},
579
    {"1length", zlength},
580
    {"3put", zput},
581
    {"3putinterval", zputinterval},
582
                /* Internal operators */
583
    {"0%array_continue", array_continue},
584
    {"0%dict_continue", dict_continue},
585
    {"0%packedarray_continue", packedarray_continue},
586
    {"0%string_continue", string_continue},
587
    op_def_end(0)
588
};
589
590
/* ------ Shared routines ------ */
591
592
/* Copy an interval from one operand to another. */
593
/* This is used by both putinterval and string/array copy. */
594
/* The destination is known to be an array or string, */
595
/* and the starting index is known to be less than or equal to */
596
/* its length; nothing else has been checked. */
597
static int
598
copy_interval(i_ctx_t *i_ctx_p /* for ref_assign_old */, os_ptr prto,
599
              uint index, os_ptr prfrom, client_name_t cname)
600
3.85M
{
601
3.85M
    int fromtype = r_type(prfrom);
602
3.85M
    uint fromsize = r_size(prfrom);
603
604
3.85M
    if (!(fromtype == r_type(prto) ||
605
3.85M
          ((fromtype == t_shortarray || fromtype == t_mixedarray) &&
606
9.78k
           r_type(prto) == t_array))
607
3.85M
        )
608
3.85M
        return_op_typecheck(prfrom);
609
3.85M
    check_read(*prfrom);
610
3.85M
    check_write(*prto);
611
3.85M
    if (fromsize > r_size(prto) - index)
612
0
        return_error(gs_error_rangecheck);
613
3.85M
    switch (fromtype) {
614
1.48M
        case t_array:
615
1.48M
            {     /* We have to worry about aliasing, */
616
                /* but refcpy_to_old takes care of it for us. */
617
1.48M
                return refcpy_to_old(prto, index, prfrom->value.refs,
618
1.48M
                                     fromsize, idmemory, cname);
619
0
            }
620
2.35M
        case t_string:
621
2.35M
            { /* memmove takes care of aliasing. */
622
2.35M
                memmove(prto->value.bytes + index, prfrom->value.bytes,
623
2.35M
                        fromsize);
624
2.35M
            }
625
2.35M
            break;
626
9.78k
        case t_mixedarray:
627
9.78k
        case t_shortarray:
628
9.78k
            { /* We don't have to worry about aliasing, because */
629
                /* packed arrays are read-only and hence the destination */
630
                /* can't be a packed array. */
631
9.78k
                uint i;
632
9.78k
                const ref_packed *packed = prfrom->value.packed;
633
9.78k
                ref *pdest = prto->value.refs + index;
634
9.78k
                ref elt;
635
636
2.51M
                for (i = 0; i < fromsize; i++, pdest++) {
637
2.50M
                    packed_get(imemory, packed, &elt);
638
2.50M
                    ref_assign_old(prto, pdest, &elt, cname);
639
2.50M
                    packed = packed_next(packed);
640
2.50M
                }
641
9.78k
            }
642
9.78k
            break;
643
3.85M
    }
644
2.36M
    return 0;
645
3.85M
}