Commit | Line | Data |
---|---|---|
7888f053 WJ |
1 | /* Copyright (C) 1990, 1992 Aladdin Enterprises. All rights reserved. |
2 | Distributed by Free Software Foundation, Inc. | |
3 | ||
4 | This file is part of Ghostscript. | |
5 | ||
6 | Ghostscript is distributed in the hope that it will be useful, but | |
7 | WITHOUT ANY WARRANTY. No author or distributor accepts responsibility | |
8 | to anyone for the consequences of using it or for whether it serves any | |
9 | particular purpose or works at all, unless he says so in writing. Refer | |
10 | to the Ghostscript General Public License for full details. | |
11 | ||
12 | Everyone is granted permission to copy, modify and redistribute | |
13 | Ghostscript, but only under the conditions described in the Ghostscript | |
14 | General Public License. A copy of this license is supposed to have been | |
15 | given to you along with Ghostscript so you can know your rights and | |
16 | responsibilities. It should be in a file named COPYING. Among other | |
17 | things, the copyright notice and this notice must be preserved on all | |
18 | copies. */ | |
19 | ||
20 | /* zpacked.c */ | |
21 | /* Packed array operators for Ghostscript */ | |
22 | #include "ghost.h" | |
23 | #include "errors.h" | |
24 | #include "alloc.h" | |
25 | #include "dict.h" | |
26 | #include "name.h" | |
27 | #include "oper.h" | |
28 | #include "packed.h" | |
29 | #include "save.h" /* for alloc_refs */ | |
30 | #include "store.h" | |
31 | ||
32 | /* Import the array packing flag */ | |
33 | extern ref array_packing; | |
34 | ||
35 | /* currentpacking */ | |
36 | int | |
37 | zcurrentpacking(register os_ptr op) | |
38 | { push(1); | |
39 | make_bool(op, array_packing.value.index); | |
40 | return 0; | |
41 | } | |
42 | ||
43 | /* packedarray */ | |
44 | int | |
45 | zpackedarray(register os_ptr op) | |
46 | { int code; | |
47 | uint size; | |
48 | os_ptr aop; | |
49 | check_type(*op, t_integer); | |
50 | if ( op->value.intval < 0 || | |
51 | op->value.intval > max_uint / sizeof(ref) - 1 | |
52 | ) | |
53 | return e_rangecheck; | |
54 | size = op->value.intval; | |
55 | if ( size > op - osbot ) return e_stackunderflow; | |
56 | aop = op - size; | |
57 | code = make_packed_array(aop, size, aop, "packedarray"); | |
58 | if ( code >= 0 ) | |
59 | { pop(size); | |
60 | } | |
61 | return code; | |
62 | } | |
63 | ||
64 | /* setpacking */ | |
65 | int | |
66 | zsetpacking(register os_ptr op) | |
67 | { check_type(*op, t_boolean); | |
68 | ref_save(&array_packing, "setpacking"); | |
69 | array_packing.value.index = op->value.index; | |
70 | pop(1); | |
71 | return 0; | |
72 | } | |
73 | ||
74 | /* ------ Non-operator routines ------ */ | |
75 | ||
76 | /* Make a packed array. See the comment in packed.h about */ | |
77 | /* ensuring that refs in mixed arrays are properly aligned. */ | |
78 | int | |
79 | make_packed_array(ref *elts, uint size, ref *paref, const char *client_name) | |
80 | { /* Check whether we can make a packed array. */ | |
81 | ref *endp = elts + size; | |
82 | ref *pref = elts; | |
83 | ushort *pbody, *pdest; | |
84 | ushort *pshort; /* points to start of */ | |
85 | /* last run of short elements */ | |
86 | int atype; | |
87 | /* Allocate a maximum-size array first, */ | |
88 | /* shorten later if needed. */ | |
89 | pbody = (ushort *)alloc(size, sizeof(ref), client_name); | |
90 | if ( pbody == 0 ) return e_VMerror; | |
91 | pshort = pdest = pbody; | |
92 | for ( ; pref < endp; pref++ ) | |
93 | { switch ( r_btype(pref) ) /* not r_type, opers are special */ | |
94 | { | |
95 | case t_name: | |
96 | if ( name_index(pref) >= packed_max_name_index ) | |
97 | break; /* can't pack */ | |
98 | *pdest = name_index(pref) + | |
99 | (r_has_attr(pref, a_executable) ? | |
100 | pt_tag(pt_executable_name) : | |
101 | pt_tag(pt_literal_name)); | |
102 | pdest++; | |
103 | continue; | |
104 | case t_integer: | |
105 | if ( pref->value.intval < packed_min_intval || | |
106 | pref->value.intval > packed_max_intval | |
107 | ) | |
108 | break; | |
109 | *pdest = pt_tag(pt_integer) + | |
110 | ((short)pref->value.intval - packed_min_intval); | |
111 | pdest++; | |
112 | continue; | |
113 | case t_oparray: | |
114 | case t_operator: | |
115 | { uint oidx; | |
116 | if ( !r_has_attr(pref, a_executable) ) break; | |
117 | oidx = op_index(pref); | |
118 | if ( oidx == 0 || oidx > packed_int_mask ) break; | |
119 | *pdest = pt_tag(pt_executable_operator) + oidx; | |
120 | } pdest++; | |
121 | continue; | |
122 | default: ; | |
123 | } | |
124 | /* Can't pack this element, use a full ref. */ | |
125 | /* We may have to unpack up to 3 preceding short elements. */ | |
126 | { int i = (pdest - pshort) & 3; | |
127 | ref *pnext = (ref *)(pdest + (packed_per_ref - 1) * i); | |
128 | ref *pnext1 = pnext; | |
129 | ref temp; /* source & dest might overlap */ | |
130 | while ( --i >= 0 ) | |
131 | { packed_get(--pdest, &temp); | |
132 | --pnext; | |
133 | ref_assign(pnext, &temp); | |
134 | } | |
135 | pdest = (ushort *)pnext1; | |
136 | ref_assign(&temp, pref); | |
137 | ref_assign_new(pnext1, &temp); | |
138 | } | |
139 | pdest += packed_per_ref; | |
140 | pshort = pdest; | |
141 | } | |
142 | atype = (pdest == pbody + size ? t_shortarray : t_mixedarray); | |
143 | pbody = (ushort *)alloc_shrink((byte *)pbody, size * packed_per_ref, | |
144 | (uint)(pdest - pbody), sizeof(ushort), | |
145 | client_name); | |
146 | make_tasv_new(paref, atype, a_read+a_execute, size, packed, pbody); | |
147 | return 0; | |
148 | } | |
149 | ||
150 | /* Get an element from a packed array. */ | |
151 | /* (This works for ordinary arrays too.) */ | |
152 | void | |
153 | packed_get(const ushort *packed, ref *pref) | |
154 | { ushort elt = *packed; | |
155 | switch ( elt >> packed_type_shift ) | |
156 | { | |
157 | case pt_executable_operator: | |
158 | op_index_ref(elt & packed_int_mask, pref); | |
159 | break; | |
160 | case pt_integer: | |
161 | make_int(pref, (elt & packed_int_mask) + packed_min_intval); | |
162 | break; | |
163 | case pt_literal_name: | |
164 | case pt_literal_name + 1: | |
165 | name_index_ref(elt & packed_max_name_index, pref); | |
166 | break; | |
167 | case pt_executable_name: | |
168 | case pt_executable_name + 1: | |
169 | name_index_ref(elt & packed_max_name_index, pref); | |
170 | r_set_attrs(pref, a_executable); | |
171 | break; | |
172 | default: /* (shouldn't happen) */ | |
173 | case pt_full_ref: | |
174 | ref_assign(pref, (const ref *)packed); | |
175 | } | |
176 | } | |
177 | ||
178 | /* Skip N elements in a packed array. */ | |
179 | /* (This works for ordinary arrays too.) */ | |
180 | void | |
181 | packed_skip(ushort **pp, uint count) | |
182 | { ushort *packed = *pp; | |
183 | while ( count-- > 0 ) | |
184 | if ( *packed <= packed_max_full_ref ) | |
185 | packed += packed_per_ref; /* full ref */ | |
186 | else | |
187 | packed++; | |
188 | *pp = packed; | |
189 | } | |
190 | ||
191 | /* ------ Initialization procedure ------ */ | |
192 | ||
193 | op_def zpacked_op_defs[] = { | |
194 | {"0currentpacking", zcurrentpacking}, | |
195 | {"1packedarray", zpackedarray}, | |
196 | {"1setpacking", zsetpacking}, | |
197 | op_def_end(0) | |
198 | }; |