1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied, modified
8
or distributed except as expressly authorized under the terms of that
9
license. Refer to licensing information at http://www.artifex.com/
10
or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11
San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
14
/* $Id: zgeneric.c 9043 2008-08-28 22:48:19Z giles $ */
15
/* Array/string/dictionary generic operators for PostScript */
18
#include "gsstruct.h" /* for st_bytes */
20
#include "dstack.h" /* for systemdict */
21
#include "estack.h" /* for forall */
28
/* This file implements copy, get, put, getinterval, putinterval, */
29
/* length, and forall, which apply generically to */
30
/* arrays, strings, and dictionaries. (Copy also has a special */
31
/* meaning for copying the top N elements of the stack.) */
33
/* See the comment in opdef.h for an invariant which allows */
34
/* more efficient implementation of forall. */
36
/* Forward references */
37
static int zcopy_integer(i_ctx_t *);
38
static int zcopy_interval(i_ctx_t *);
39
static int copy_interval(i_ctx_t *, os_ptr, uint, os_ptr, client_name_t);
41
/* <various1> <various2> copy <various> */
42
/* <obj1> ... <objn> <int> copy <obj1> ... <objn> <obj1> ... <objn> */
43
/* Note that this implements copy for arrays and strings, */
44
/* but not for dictionaries (see zcopy_dict in zdict.c). */
46
zcopy(i_ctx_t *i_ctx_p)
49
int type = r_type(op);
51
if (type == t_integer)
52
return zcopy_integer(i_ctx_p);
57
return zcopy_interval(i_ctx_p);
59
return zcopy_dict(i_ctx_p);
61
return_op_typecheck(op);
65
/* <obj1> ... <objn> <int> copy <obj1> ... <objn> <obj1> ... <objn> */
67
zcopy_integer(i_ctx_t *i_ctx_p)
74
if ((ulong) op->value.intval > (ulong)(op - osbot)) {
75
/* There might be enough elements in other blocks. */
76
check_type(*op, t_integer);
77
if (op->value.intval >= (int)ref_stack_count(&o_stack))
78
return_error(e_stackunderflow);
79
if (op->value.intval < 0)
80
return_error(e_rangecheck);
81
check_int_ltu(*op, ref_stack_count(&o_stack));
82
count = op->value.intval;
83
} else if (op1 + (count = op->value.intval) <= ostop) {
85
memcpy((char *)op, (char *)(op - count), count * sizeof(ref));
89
/* Do it the slow, general way. */
90
code = ref_stack_push(&o_stack, count - 1);
93
for (i = 0; i < count; i++)
94
*ref_stack_index(&o_stack, i) =
95
*ref_stack_index(&o_stack, i + count);
99
/* <array1> <array2> copy <subarray2> */
100
/* <string1> <string2> copy <substring2> */
102
zcopy_interval(i_ctx_t *i_ctx_p)
106
int code = copy_interval(i_ctx_p, op, 0, op1, "copy");
110
r_set_size(op, r_size(op1));
116
/* <array|dict|name|packedarray|string> length <int> */
118
zlength(i_ctx_t *i_ctx_p)
121
switch (r_type(op)) {
127
make_int(op, r_size(op));
130
check_dict_read(*op);
131
make_int(op, dict_length(op));
136
name_string_ref(imemory, op, &str);
137
make_int(op, r_size(&str));
141
if (gs_object_type(imemory, op->value.pstruct) != &st_bytes)
142
return_error(e_typecheck);
144
make_int(op, gs_object_size(imemory, op->value.pstruct));
147
return_op_typecheck(op);
151
/* <array|packedarray|string> <index> get <obj> */
152
/* <dict> <key> get <obj> */
154
zget(i_ctx_t *i_ctx_p)
161
switch (r_type(op1)) {
163
check_dict_read(*op1);
164
if (dict_find(op1, op, &pvalue) <= 0)
165
return_error(e_undefined);
170
check_int_ltu(*op, r_size(op1));
171
make_int(op1, op1->value.bytes[(uint) op->value.intval]);
176
check_type(*op, t_integer);
178
code = array_get(imemory, op1, op->value.intval, op1);
183
return_error(e_stackunderflow);
185
return_error(e_typecheck);
191
/* <array> <index> <obj> put - */
192
/* <dict> <key> <value> put - */
193
/* <string> <index> <int> put - */
195
zput(i_ctx_t *i_ctx_p)
199
os_ptr op2 = op1 - 1;
203
switch (r_type(op2)) {
205
if (i_ctx_p->in_superexec == 0)
206
check_dict_write(*op2);
208
int code = idict_put(op2, op1, op);
211
return code; /* error */
216
check_int_ltu(*op1, r_size(op2));
217
store_check_dest(op2, op);
219
ref *eltp = op2->value.refs + (uint) op1->value.intval;
221
ref_assign_old(op2, eltp, op, "put");
224
case t_mixedarray: /* packed arrays are read-only */
226
return_error(e_invalidaccess);
228
sdata = op2->value.bytes;
230
str: check_write(*op2);
231
check_int_ltu(*op1, ssize);
232
check_int_leu(*op, 0xff);
233
sdata[(uint)op1->value.intval] = (byte)op->value.intval;
236
if (gs_object_type(imemory, op2->value.pstruct) != &st_bytes)
237
return_error(e_typecheck);
238
sdata = r_ptr(op2, byte);
239
ssize = gs_object_size(imemory, op2->value.pstruct);
242
return_op_typecheck(op2);
248
/* <array> <index> <obj> .forceput - */
249
/* <dict> <key> <value> .forceput - */
251
* This forces a "put" even if the object is not writable, and (if the
252
* object is systemdict or the save level is 0) even if the value is in
253
* local VM. It is meant to be used only for replacing the value of
254
* FontDirectory in systemdict when switching between local and global VM,
255
* and a few similar applications. After initialization, this operator
256
* should no longer be accessible by name.
259
zforceput(i_ctx_t *i_ctx_p)
266
switch (r_type(op2)) {
268
check_int_ltu(*op1, r_size(op2));
269
if (r_space(op2) > r_space(op)) {
270
if (imemory_save_level(iimemory))
271
return_error(e_invalidaccess);
274
ref *eltp = op2->value.refs + (uint) op1->value.intval;
276
ref_assign_old(op2, eltp, op, "put");
280
if (op2->value.pdict == systemdict->value.pdict ||
281
!imemory_save_level(iimemory)
283
uint space = r_space(op2);
285
r_set_space(op2, avm_local);
286
code = idict_put(op2, op1, op);
287
r_set_space(op2, space);
289
code = idict_put(op2, op1, op);
294
return_error(e_typecheck);
300
/* <seq:array|packedarray|string> <index> <count> getinterval <subseq> */
302
zgetinterval(i_ctx_t *i_ctx_p)
306
os_ptr op2 = op1 - 1;
310
switch (r_type(op2)) {
312
return_op_typecheck(op2);
319
check_int_leu(*op1, r_size(op2));
320
index = op1->value.intval;
321
check_int_leu(*op, r_size(op2) - index);
322
count = op->value.intval;
323
switch (r_type(op2)) {
325
op2->value.refs += index;
328
op2->value.bytes += index;
331
const ref_packed *packed = op2->value.packed;
334
packed = packed_next(packed);
335
op2->value.packed = packed;
339
op2->value.packed += index;
342
r_set_size(op2, count);
347
/* <array1> <index> <array2|packedarray2> putinterval - */
348
/* <string1> <index> <string2> putinterval - */
349
/* <bytestring1> <index> <string2> putinterval - */
351
zputinterval(i_ctx_t *i_ctx_p)
354
os_ptr opindex = op - 1;
355
os_ptr opto = opindex - 1;
358
switch (r_type(opto)) {
360
return_error(e_typecheck);
362
if (r_type(op) != t_array && r_type(op) != t_string && r_type(op) != t__invalid)
363
return_error(e_typecheck); /* to match Distiller */
365
return_error(e_stackunderflow);
368
return_error(e_invalidaccess);
372
check_int_leu(*opindex, r_size(opto));
373
code = copy_interval(i_ctx_p, opto, (uint)(opindex->value.intval),
377
uint dsize, ssize, index;
380
if (gs_object_type(imemory, opto->value.pstruct) != &st_bytes)
381
return_error(e_typecheck);
382
dsize = gs_object_size(imemory, opto->value.pstruct);
383
check_int_leu(*opindex, dsize);
384
index = (uint)opindex->value.intval;
385
check_read_type(*op, t_string);
387
if (ssize > dsize - index)
388
return_error(e_rangecheck);
389
memcpy(r_ptr(opto, byte) + index, op->value.const_bytes, ssize);
399
/* <array|packedarray|string> <<element> proc> forall - */
400
/* <dict> <<key> <value> proc> forall - */
402
array_continue(i_ctx_t *),
403
dict_continue(i_ctx_t *),
404
string_continue(i_ctx_t *),
405
packedarray_continue(i_ctx_t *);
406
static int forall_cleanup(i_ctx_t *);
408
zforall(i_ctx_t *i_ctx_p)
413
es_ptr cproc = ep + 4;
417
switch (r_type(obj)) {
419
return_op_typecheck(obj);
422
make_op_estack(cproc, array_continue);
425
check_dict_read(*obj);
426
make_int(cproc, dict_first(obj));
428
make_op_estack(cproc, dict_continue);
432
make_op_estack(cproc, string_continue);
437
make_op_estack(cproc, packedarray_continue);
443
* - the composite object;
445
* - the iteration index (only for dictionaries, done above);
446
* and invoke the continuation operator.
448
make_mark_estack(ep + 1, es_for, forall_cleanup);
453
return (*real_opproc(cproc))(i_ctx_p);
455
/* Continuation operator for arrays */
457
array_continue(i_ctx_t *i_ctx_p)
460
es_ptr obj = esp - 1;
462
if (r_size(obj)) { /* continue */
465
*op = *obj->value.refs;
469
return o_push_estack;
471
esp -= 3; /* pop mark, object, proc */
475
/* Continuation operator for dictionaries */
477
dict_continue(i_ctx_t *i_ctx_p)
480
es_ptr obj = esp - 2;
481
int index = (int)esp->value.intval;
483
push(2); /* make room for key and value */
484
if ((index = dict_next(obj, index, op - 1)) >= 0) { /* continue */
485
esp->value.intval = index;
488
return o_push_estack;
490
pop(2); /* undo push */
491
esp -= 4; /* pop mark, object, proc, index */
495
/* Continuation operator for strings */
497
string_continue(i_ctx_t *i_ctx_p)
500
es_ptr obj = esp - 1;
502
if (r_size(obj)) { /* continue */
505
make_int(op, *obj->value.bytes);
509
return o_push_estack;
511
esp -= 3; /* pop mark, object, proc */
515
/* Continuation operator for packed arrays */
517
packedarray_continue(i_ctx_t *i_ctx_p)
520
es_ptr obj = esp - 1;
522
if (r_size(obj)) { /* continue */
523
const ref_packed *packed = obj->value.packed;
527
packed_get(imemory, packed, op);
528
obj->value.packed = packed_next(packed);
531
return o_push_estack;
533
esp -= 3; /* pop mark, object, proc */
537
/* Vacuous cleanup procedure */
539
forall_cleanup(i_ctx_t *i_ctx_p)
544
/* ------ Initialization procedure ------ */
546
const op_def zgeneric_op_defs[] =
549
{"2forall", zforall},
550
{"3.forceput", zforceput},
552
{"3getinterval", zgetinterval},
553
{"1length", zlength},
555
{"3putinterval", zputinterval},
556
/* Internal operators */
557
{"0%array_continue", array_continue},
558
{"0%dict_continue", dict_continue},
559
{"0%packedarray_continue", packedarray_continue},
560
{"0%string_continue", string_continue},
564
/* ------ Shared routines ------ */
566
/* Copy an interval from one operand to another. */
567
/* This is used by both putinterval and string/array copy. */
568
/* The destination is known to be an array or string, */
569
/* and the starting index is known to be less than or equal to */
570
/* its length; nothing else has been checked. */
572
copy_interval(i_ctx_t *i_ctx_p /* for ref_assign_old */, os_ptr prto,
573
uint index, os_ptr prfrom, client_name_t cname)
575
int fromtype = r_type(prfrom);
576
uint fromsize = r_size(prfrom);
578
if (!(fromtype == r_type(prto) ||
579
((fromtype == t_shortarray || fromtype == t_mixedarray) &&
580
r_type(prto) == t_array))
582
return_op_typecheck(prfrom);
585
if (fromsize > r_size(prto) - index)
586
return_error(e_rangecheck);
589
{ /* We have to worry about aliasing, */
590
/* but refcpy_to_old takes care of it for us. */
591
return refcpy_to_old(prto, index, prfrom->value.refs,
592
fromsize, idmemory, cname);
595
{ /* memmove takes care of aliasing. */
596
memmove(prto->value.bytes + index, prfrom->value.bytes,
602
{ /* We don't have to worry about aliasing, because */
603
/* packed arrays are read-only and hence the destination */
604
/* can't be a packed array. */
606
const ref_packed *packed = prfrom->value.packed;
607
ref *pdest = prto->value.refs + index;
610
for (i = 0; i < fromsize; i++, pdest++) {
611
packed_get(imemory, packed, &elt);
612
ref_assign_old(prto, pdest, &elt, cname);
613
packed = packed_next(packed);