Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/psi/zgeneric.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2021 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.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, 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
500M
{
50
500M
    os_ptr op = osp;
51
500M
    int type = r_type(op);
52
53
500M
    if (type == t_integer)
54
472M
        return zcopy_integer(i_ctx_p);
55
28.5M
    check_op(2);
56
28.5M
    switch (type) {
57
11.8M
        case t_array:
58
27.3M
        case t_string:
59
27.3M
            return zcopy_interval(i_ctx_p);
60
1.24M
        case t_dictionary:
61
1.24M
            return zcopy_dict(i_ctx_p);
62
12
        default:
63
12
            return_op_typecheck(op);
64
28.5M
    }
65
28.5M
}
66
67
/* <obj1> ... <objn> <int> copy <obj1> ... <objn> <obj1> ... <objn> */
68
static int
69
zcopy_integer(i_ctx_t *i_ctx_p)
70
472M
{
71
472M
    os_ptr op = osp;
72
472M
    os_ptr op1 = op - 1;
73
472M
    int count, i;
74
472M
    int code;
75
76
472M
    if ((uint) op->value.intval > (uint)(op - osbot)) {
77
        /* There might be enough elements in other blocks. */
78
41
        check_type(*op, t_integer);
79
41
        if (op->value.intval >= (int)ref_stack_count(&o_stack))
80
20
            return_error(gs_error_stackunderflow);
81
21
        if (op->value.intval < 0)
82
21
            return_error(gs_error_rangecheck);
83
21
        check_int_ltu(*op, ref_stack_count(&o_stack));
84
0
        count = op->value.intval;
85
472M
    } else if (op1 + (count = op->value.intval) <= ostop) {
86
        /* Fast case. */
87
472M
        memcpy((char *)op, (char *)(op - count), count * sizeof(ref));
88
472M
        push(count - 1);
89
472M
        return 0;
90
472M
    }
91
    /* Do it the slow, general way. */
92
57
    code = ref_stack_push(&o_stack, count - 1);
93
57
    if (code < 0)
94
0
        return code;
95
279
    for (i = 0; i < count; i++)
96
222
        *ref_stack_index(&o_stack, i) =
97
222
            *ref_stack_index(&o_stack, i + count);
98
57
    return 0;
99
57
}
100
101
/* <array1> <array2> copy <subarray2> */
102
/* <string1> <string2> copy <substring2> */
103
static int
104
zcopy_interval(i_ctx_t *i_ctx_p)
105
27.3M
{
106
27.3M
    os_ptr op = osp;
107
27.3M
    os_ptr op1 = op - 1;
108
27.3M
    int code = copy_interval(i_ctx_p, op, 0, op1, "copy");
109
110
27.3M
    if (code < 0)
111
2
        return code;
112
27.3M
    r_set_size(op, r_size(op1));
113
27.3M
    *op1 = *op;
114
27.3M
    pop(1);
115
27.3M
    return 0;
116
27.3M
}
117
118
/* <array|dict|name|packedarray|string> length <int> */
119
static int
120
zlength(i_ctx_t *i_ctx_p)
121
294M
{
122
294M
    os_ptr op = osp;
123
294M
    switch (r_type(op)) {
124
28.4M
        case t_array:
125
207M
        case t_string:
126
208M
        case t_mixedarray:
127
209M
        case t_shortarray:
128
209M
            check_read(*op);
129
209M
            make_int(op, r_size(op));
130
209M
            return 0;
131
83.5M
        case t_dictionary:
132
83.5M
            check_dict_read(*op);
133
83.5M
            make_int(op, dict_length(op));
134
83.5M
            return 0;
135
1.25M
        case t_name: {
136
1.25M
            ref str;
137
138
1.25M
            name_string_ref(imemory, op, &str);
139
1.25M
            make_int(op, r_size(&str));
140
1.25M
            return 0;
141
83.5M
        }
142
3
        case t_astruct:
143
3
            if (gs_object_type(imemory, op->value.pstruct) != &st_bytes)
144
3
                return_error(gs_error_typecheck);
145
0
            check_read(*op);
146
0
            make_int(op, gs_object_size(imemory, op->value.pstruct));
147
0
            return 0;
148
20
        default:
149
20
            return_op_typecheck(op);
150
294M
    }
151
294M
}
152
153
/* <array|packedarray|string> <index> get <obj> */
154
/* <dict> <key> get <obj> */
155
static int
156
zget(i_ctx_t *i_ctx_p)
157
1.04G
{
158
1.04G
    int code;
159
1.04G
    os_ptr op = osp;
160
1.04G
    os_ptr op1 = op - 1;
161
1.04G
    ref *pvalue;
162
163
1.04G
    switch (r_type(op1)) {
164
211M
        case t_dictionary:
165
211M
            check_dict_read(*op1);
166
211M
            if (dict_find(op1, op, &pvalue) <= 0)
167
24
                return_error(gs_error_undefined);
168
211M
            op[-1] = *pvalue;
169
211M
            break;
170
250M
        case t_string:
171
250M
            check_read(*op1);
172
250M
            check_int_ltu(*op, r_size(op1));
173
250M
            make_int(op1, op1->value.bytes[(uint) op->value.intval]);
174
250M
            break;
175
531M
        case t_array:
176
555M
        case t_mixedarray:
177
579M
        case t_shortarray:
178
579M
            check_type(*op, t_integer);
179
579M
            check_read(*op1);
180
579M
            code = array_get(imemory, op1, op->value.intval, op1);
181
579M
            if (code < 0)
182
1
                return code;
183
579M
            break;
184
579M
        case t__invalid:
185
13
            return_error(gs_error_stackunderflow);
186
29
        default:
187
29
            return_error(gs_error_typecheck);
188
1.04G
    }
189
1.04G
    pop(1);
190
1.04G
    return 0;
191
1.04G
}
192
193
/* <array> <index> <obj> put - */
194
/* <dict> <key> <value> put - */
195
/* <string> <index> <int> put - */
196
static int
197
zput(i_ctx_t *i_ctx_p)
198
1.19G
{
199
1.19G
    os_ptr op = osp;
200
1.19G
    os_ptr op1 = op - 1;
201
1.19G
    os_ptr op2 = op1 - 1;
202
1.19G
    byte *sdata;
203
1.19G
    uint ssize;
204
205
1.19G
    switch (r_type(op2)) {
206
1.04G
        case t_dictionary:
207
1.04G
            check_dict_write(*op2);
208
1.04G
            {
209
1.04G
                int code = idict_put(op2, op1, op);
210
211
1.04G
                if (code < 0)
212
0
                    return code; /* error */
213
1.04G
            }
214
1.04G
            break;
215
1.04G
        case t_array:
216
43.0M
            check_write(*op2);
217
43.0M
            check_int_ltu(*op1, r_size(op2));
218
43.0M
            store_check_dest(op2, op);
219
43.0M
            {
220
43.0M
                ref *eltp = op2->value.refs + (uint) op1->value.intval;
221
222
43.0M
                ref_assign_old(op2, eltp, op, "put");
223
43.0M
            }
224
43.0M
            break;
225
0
        case t_mixedarray:  /* packed arrays are read-only */
226
0
        case t_shortarray:
227
0
            return_error(gs_error_invalidaccess);
228
103M
        case t_string:
229
103M
            sdata = op2->value.bytes;
230
103M
            ssize = r_size(op2);
231
103M
str:      check_write(*op2);
232
103M
            check_int_ltu(*op1, ssize);
233
103M
            check_int_leu(*op, 0xff);
234
103M
            sdata[(uint)op1->value.intval] = (byte)op->value.intval;
235
103M
            break;
236
0
        case t_astruct:
237
0
            if (gs_object_type(imemory, op2->value.pstruct) != &st_bytes)
238
0
                return_error(gs_error_typecheck);
239
0
            sdata = r_ptr(op2, byte);
240
0
            ssize = gs_object_size(imemory, op2->value.pstruct);
241
0
            goto str;
242
15
        default:
243
15
            return_op_typecheck(op2);
244
1.19G
    }
245
1.19G
    pop(3);
246
1.19G
    return 0;
247
1.19G
}
248
249
/* <array> <index> <obj> .forceput - */
250
/* <dict> <key> <value> .forceput - */
251
/*
252
 * This forces a "put" even if the object is not writable, and (if the
253
 * object is systemdict or the save level is 0) even if the value is in
254
 * local VM.  It is meant to be used only for replacing the value of
255
 * FontDirectory in systemdict when switching between local and global VM,
256
 * and a few similar applications.  After initialization, this operator
257
 * should no longer be accessible by name.
258
 */
259
static int
260
zforceput(i_ctx_t *i_ctx_p)
261
42.0M
{
262
42.0M
    os_ptr op = osp;
263
42.0M
    os_ptr op1 = op - 1;
264
42.0M
    os_ptr op2 = op - 2;
265
42.0M
    int code;
266
267
42.0M
    switch (r_type(op2)) {
268
89.2k
    case t_array:
269
89.2k
        check_int_ltu(*op1, r_size(op2));
270
89.2k
        if (r_space(op2) > r_space(op)) {
271
0
            if (imemory_save_level(iimemory))
272
0
                return_error(gs_error_invalidaccess);
273
0
        }
274
89.2k
        {
275
89.2k
            ref *eltp = op2->value.refs + (uint) op1->value.intval;
276
277
89.2k
            ref_assign_old(op2, eltp, op, "put");
278
89.2k
        }
279
89.2k
        break;
280
41.9M
    case t_dictionary:
281
41.9M
        if (op2->value.pdict == systemdict->value.pdict ||
282
41.9M
            !imemory_save_level(iimemory)
283
41.9M
            ) {
284
40.8M
            uint space = r_space(op2);
285
286
40.8M
            r_set_space(op2, avm_local);
287
40.8M
            code = idict_put(op2, op1, op);
288
40.8M
            r_set_space(op2, space);
289
40.8M
        } else
290
1.17M
            code = idict_put(op2, op1, op);
291
41.9M
        if (code < 0)
292
1
            return code;
293
41.9M
        break;
294
41.9M
    default:
295
0
        return_error(gs_error_typecheck);
296
42.0M
    }
297
42.0M
    pop(3);
298
42.0M
    return 0;
299
42.0M
}
300
301
/* <seq:array|packedarray|string> <index> <count> getinterval <subseq> */
302
static int
303
zgetinterval(i_ctx_t *i_ctx_p)
304
35.7M
{
305
35.7M
    os_ptr op = osp;
306
35.7M
    os_ptr op1 = op - 1;
307
35.7M
    os_ptr op2 = op1 - 1;
308
35.7M
    uint index;
309
35.7M
    uint count;
310
311
35.7M
    switch (r_type(op2)) {
312
14
        default:
313
14
            return_op_typecheck(op2);
314
2.19M
        case t_array:
315
24.0M
        case t_string:
316
35.7M
        case t_mixedarray:
317
35.7M
        case t_shortarray:;
318
35.7M
    }
319
35.7M
    check_read(*op2);
320
35.7M
    check_int_leu(*op1, r_size(op2));
321
35.7M
    index = op1->value.intval;
322
35.7M
    check_int_leu(*op, r_size(op2) - index);
323
35.7M
    count = op->value.intval;
324
35.7M
    switch (r_type(op2)) {
325
2.19M
        case t_array:
326
2.19M
            op2->value.refs += index;
327
2.19M
            break;
328
21.8M
        case t_string:
329
21.8M
            op2->value.bytes += index;
330
21.8M
            break;
331
11.7M
        case t_mixedarray: {
332
11.7M
            const ref_packed *packed = op2->value.packed;
333
334
107M
            for (; index--;)
335
95.4M
                packed = packed_next(packed);
336
11.7M
            op2->value.packed = packed;
337
11.7M
            break;
338
0
        }
339
0
        case t_shortarray:
340
0
            op2->value.packed += index;
341
0
            break;
342
35.7M
    }
343
35.7M
    r_set_size(op2, count);
344
35.7M
    pop(2);
345
35.7M
    return 0;
346
35.7M
}
347
348
/* <array1> <index> <array2|packedarray2> putinterval - */
349
/* <string1> <index> <string2> putinterval - */
350
/* <bytestring1> <index> <string2> putinterval - */
351
static int
352
zputinterval(i_ctx_t *i_ctx_p)
353
12.2M
{
354
12.2M
    os_ptr op = osp;
355
12.2M
    os_ptr opindex = op - 1;
356
12.2M
    os_ptr opto = opindex - 1;
357
12.2M
    int code;
358
359
12.2M
    switch (r_type(opto)) {
360
6
        default:
361
6
            return_error(gs_error_typecheck);
362
16
        case t__invalid:
363
16
            if (r_type(op) != t_array && r_type(op) != t_string && r_type(op) != t__invalid)
364
6
                return_error(gs_error_typecheck); /* to match Distiller */
365
10
            else
366
10
                return_error(gs_error_stackunderflow);
367
0
        case t_mixedarray:
368
0
        case t_shortarray:
369
0
            return_error(gs_error_invalidaccess);
370
1.70M
        case t_array:
371
12.2M
        case t_string:
372
12.2M
            check_write(*opto);
373
12.2M
            check_int_leu(*opindex, r_size(opto));
374
12.2M
            code = copy_interval(i_ctx_p, opto, (uint)(opindex->value.intval),
375
12.2M
                                 op, "putinterval");
376
12.2M
            break;
377
0
        case t_astruct: {
378
0
            uint dsize, ssize, index;
379
380
0
            check_write(*opto);
381
0
            if (gs_object_type(imemory, opto->value.pstruct) != &st_bytes)
382
0
                return_error(gs_error_typecheck);
383
0
            dsize = gs_object_size(imemory, opto->value.pstruct);
384
0
            check_int_leu(*opindex, dsize);
385
0
            index = (uint)opindex->value.intval;
386
0
            check_read_type(*op, t_string);
387
0
            ssize = r_size(op);
388
0
            if (ssize > dsize - index)
389
0
                return_error(gs_error_rangecheck);
390
0
            memcpy(r_ptr(opto, byte) + index, op->value.const_bytes, ssize);
391
0
            code = 0;
392
0
            break;
393
0
        }
394
12.2M
    }
395
12.2M
    if (code >= 0)
396
12.2M
        pop(3);
397
12.2M
    return code;
398
12.2M
}
399
400
/* <array|packedarray|string> <<element> proc> forall - */
401
/* <dict> <<key> <value> proc> forall - */
402
static int
403
    array_continue(i_ctx_t *),
404
    dict_continue(i_ctx_t *),
405
    string_continue(i_ctx_t *),
406
    packedarray_continue(i_ctx_t *);
407
static int forall_cleanup(i_ctx_t *);
408
static int
409
zforall(i_ctx_t *i_ctx_p)
410
51.0M
{
411
51.0M
    os_ptr op = osp;
412
51.0M
    os_ptr obj = op - 1;
413
51.0M
    es_ptr ep = esp;
414
51.0M
    es_ptr cproc = ep + 4;
415
416
51.0M
    check_estack(6);
417
51.0M
    check_proc(*op);
418
51.0M
    switch (r_type(obj)) {
419
29
        default:
420
29
            return_op_typecheck(obj);
421
10.3M
        case t_array:
422
10.3M
            check_read(*obj);
423
10.3M
            make_op_estack(cproc, array_continue);
424
10.3M
            break;
425
34.9M
        case t_dictionary:
426
34.9M
            check_dict_read(*obj);
427
34.9M
            make_int(cproc, dict_first(obj));
428
34.9M
            ++cproc;
429
34.9M
            make_op_estack(cproc, dict_continue);
430
34.9M
            break;
431
178k
        case t_string:
432
178k
            check_read(*obj);
433
178k
            make_op_estack(cproc, string_continue);
434
178k
            break;
435
4.23M
        case t_mixedarray:
436
5.48M
        case t_shortarray:
437
5.48M
            check_read(*obj);
438
5.48M
            make_op_estack(cproc, packedarray_continue);
439
5.48M
            break;
440
51.0M
    }
441
    /*
442
     * Push:
443
     *   - a mark;
444
     *   - the composite object;
445
     *   - the procedure;
446
     *   - the iteration index (only for dictionaries, done above);
447
     * and invoke the continuation operator.
448
     */
449
51.0M
    make_mark_estack(ep + 1, es_for, forall_cleanup);
450
51.0M
    ep[2] = *obj;
451
51.0M
    ep[3] = *op;
452
51.0M
    esp = cproc - 1;
453
51.0M
    ref_stack_pop(&o_stack, 2);
454
51.0M
    return (*real_opproc(cproc))(i_ctx_p);
455
51.0M
}
456
/* Continuation operator for arrays */
457
static int
458
array_continue(i_ctx_t *i_ctx_p)
459
119M
{
460
119M
    os_ptr op = osp;
461
119M
    es_ptr obj = esp - 1;
462
463
119M
    if (r_size(obj)) {   /* continue */
464
109M
        push(1);
465
109M
        r_dec_size(obj, 1);
466
109M
        *op = *obj->value.refs;
467
109M
        obj->value.refs++;
468
109M
        esp += 2;
469
109M
        *esp = obj[1];
470
109M
        return o_push_estack;
471
109M
    } else {     /* done */
472
10.1M
        esp -= 3;    /* pop mark, object, proc */
473
10.1M
        return o_pop_estack;
474
10.1M
    }
475
119M
}
476
/* Continuation operator for dictionaries */
477
static int
478
dict_continue(i_ctx_t *i_ctx_p)
479
1.38G
{
480
1.38G
    os_ptr op = osp;
481
1.38G
    es_ptr obj = esp - 2;
482
1.38G
    int index = esp->value.intval;
483
484
1.38G
    push(2);      /* make room for key and value */
485
1.38G
    if ((index = dict_next(obj, index, op - 1)) >= 0) { /* continue */
486
1.34G
        esp->value.intval = index;
487
1.34G
        esp += 2;
488
1.34G
        *esp = obj[1];
489
1.34G
        return o_push_estack;
490
1.34G
    } else {     /* done */
491
34.7M
        pop(2);      /* undo push */
492
34.7M
        esp -= 4;    /* pop mark, object, proc, index */
493
34.7M
        return o_pop_estack;
494
34.7M
    }
495
1.38G
}
496
/* Continuation operator for strings */
497
static int
498
string_continue(i_ctx_t *i_ctx_p)
499
1.24M
{
500
1.24M
    os_ptr op = osp;
501
1.24M
    es_ptr obj = esp - 1;
502
503
1.24M
    if (r_size(obj)) {   /* continue */
504
1.07M
        push(1);    /* check for result space on stack BEFORE changing string size */
505
1.07M
        r_dec_size(obj, 1); /* Bug 701550 :-O */
506
1.07M
        make_int(op, *obj->value.bytes);
507
1.07M
        obj->value.bytes++;
508
1.07M
        esp += 2;
509
1.07M
        *esp = obj[1];
510
1.07M
        return o_push_estack;
511
1.07M
    } else {     /* done */
512
178k
        esp -= 3;    /* pop mark, object, proc */
513
178k
        return o_pop_estack;
514
178k
    }
515
1.24M
}
516
/* Continuation operator for packed arrays */
517
static int
518
packedarray_continue(i_ctx_t *i_ctx_p)
519
28.1M
{
520
28.1M
    os_ptr op = osp;
521
28.1M
    es_ptr obj = esp - 1;
522
523
28.1M
    if (r_size(obj)) {   /* continue */
524
22.6M
        const ref_packed *packed = obj->value.packed;
525
526
22.6M
        r_dec_size(obj, 1);
527
22.6M
        push(1);
528
22.6M
        packed_get(imemory, packed, op);
529
22.6M
        obj->value.packed = packed_next(packed);
530
22.6M
        esp += 2;
531
22.6M
        *esp = obj[1];
532
22.6M
        return o_push_estack;
533
22.6M
    } else {     /* done */
534
5.48M
        esp -= 3;    /* pop mark, object, proc */
535
5.48M
        return o_pop_estack;
536
5.48M
    }
537
28.1M
}
538
/* Vacuous cleanup procedure */
539
static int
540
forall_cleanup(i_ctx_t *i_ctx_p)
541
455k
{
542
455k
    return 0;
543
455k
}
544
545
/* ------ Initialization procedure ------ */
546
547
const op_def zgeneric_op_defs[] =
548
{
549
    {"1copy", zcopy},
550
    {"2forall", zforall},
551
    {"3.forceput", zforceput},
552
    {"2get", zget},
553
    {"3getinterval", zgetinterval},
554
    {"1length", zlength},
555
    {"3put", zput},
556
    {"3putinterval", zputinterval},
557
                /* Internal operators */
558
    {"0%array_continue", array_continue},
559
    {"0%dict_continue", dict_continue},
560
    {"0%packedarray_continue", packedarray_continue},
561
    {"0%string_continue", string_continue},
562
    op_def_end(0)
563
};
564
565
/* ------ Shared routines ------ */
566
567
/* Copy an interval from one operand to another. */
568
/* This is used by both putinterval and string/array copy. */
569
/* The destination is known to be an array or string, */
570
/* and the starting index is known to be less than or equal to */
571
/* its length; nothing else has been checked. */
572
static int
573
copy_interval(i_ctx_t *i_ctx_p /* for ref_assign_old */, os_ptr prto,
574
              uint index, os_ptr prfrom, client_name_t cname)
575
39.5M
{
576
39.5M
    int fromtype = r_type(prfrom);
577
39.5M
    uint fromsize = r_size(prfrom);
578
579
39.5M
    if (!(fromtype == r_type(prto) ||
580
39.5M
          ((fromtype == t_shortarray || fromtype == t_mixedarray) &&
581
89.2k
           r_type(prto) == t_array))
582
39.5M
        )
583
39.5M
        return_op_typecheck(prfrom);
584
39.5M
    check_read(*prfrom);
585
39.5M
    check_write(*prto);
586
39.5M
    if (fromsize > r_size(prto) - index)
587
0
        return_error(gs_error_rangecheck);
588
39.5M
    switch (fromtype) {
589
13.4M
        case t_array:
590
13.4M
            {     /* We have to worry about aliasing, */
591
                /* but refcpy_to_old takes care of it for us. */
592
13.4M
                return refcpy_to_old(prto, index, prfrom->value.refs,
593
13.4M
                                     fromsize, idmemory, cname);
594
0
            }
595
26.0M
        case t_string:
596
26.0M
            { /* memmove takes care of aliasing. */
597
26.0M
                memmove(prto->value.bytes + index, prfrom->value.bytes,
598
26.0M
                        fromsize);
599
26.0M
            }
600
26.0M
            break;
601
89.2k
        case t_mixedarray:
602
89.2k
        case t_shortarray:
603
89.2k
            { /* We don't have to worry about aliasing, because */
604
                /* packed arrays are read-only and hence the destination */
605
                /* can't be a packed array. */
606
89.2k
                uint i;
607
89.2k
                const ref_packed *packed = prfrom->value.packed;
608
89.2k
                ref *pdest = prto->value.refs + index;
609
89.2k
                ref elt;
610
611
22.9M
                for (i = 0; i < fromsize; i++, pdest++) {
612
22.8M
                    packed_get(imemory, packed, &elt);
613
22.8M
                    ref_assign_old(prto, pdest, &elt, cname);
614
22.8M
                    packed = packed_next(packed);
615
22.8M
                }
616
89.2k
            }
617
89.2k
            break;
618
39.5M
    }
619
26.1M
    return 0;
620
39.5M
}