Commit | Line | Data |
---|---|---|
a14dfc57 WJ |
1 | /* Copyright (C) 1989, 1990, 1991 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 | /* iutil.c */ | |
21 | /* Utilities for Ghostscript interpreter */ | |
22 | #include "memory_.h" | |
23 | #include "string_.h" | |
24 | #include "ghost.h" | |
25 | #include "errors.h" | |
26 | #include "alloc.h" | |
27 | #include "dict.h" | |
28 | #include "iutil.h" /* for checking prototypes */ | |
29 | #include "name.h" | |
30 | #include "ostack.h" /* for opdef.h */ | |
31 | #include "opdef.h" /* for obj_cvs */ | |
32 | #include "store.h" | |
33 | #include "gsmatrix.h" | |
34 | #include "gxdevice.h" /* for gx_color_index */ | |
35 | #include "gzcolor.h" | |
36 | ||
37 | /* ------ Object utilities ------ */ | |
38 | ||
39 | /* Copy refs from one place to another. */ | |
40 | void | |
41 | refcpy_to_old(register ref *to, register const ref *from, register uint size, | |
42 | const char *cname) | |
43 | { while ( size-- ) ref_assign_old(to, from, cname), to++, from++; | |
44 | } | |
45 | void | |
46 | refcpy_to_new(register ref *to, register const ref *from, register uint size) | |
47 | { while ( size-- ) ref_assign_new(to, from), to++, from++; | |
48 | } | |
49 | ||
50 | /* Fill a new object with nulls. */ | |
51 | void | |
52 | refset_null(register ref *to, register uint size) | |
53 | { while ( size-- ) make_null_new(to), to++; | |
54 | } | |
55 | ||
56 | /* Compare two objects for equality. Return 1 if equal, 0 if not. */ | |
57 | int | |
58 | obj_eq(register const ref *pref1, register const ref *pref2) | |
59 | { ref nref; | |
60 | if ( r_btype(pref1) != r_btype(pref2) ) | |
61 | { /* Only a few cases need be considered here: */ | |
62 | /* integer/real, name/string, and vice versa. */ | |
63 | switch ( r_type(pref1) ) | |
64 | { | |
65 | case t_integer: | |
66 | return (r_has_type(pref2, t_real) && | |
67 | pref2->value.realval == pref1->value.intval); | |
68 | case t_real: | |
69 | return (r_has_type(pref2, t_integer) && | |
70 | pref2->value.intval == pref1->value.realval); | |
71 | case t_name: | |
72 | if ( !r_has_type(pref2, t_string) ) return 0; | |
73 | name_string_ref(pref1, &nref); | |
74 | pref1 = &nref; | |
75 | break; | |
76 | case t_string: | |
77 | if ( !r_has_type(pref2, t_name) ) return 0; | |
78 | name_string_ref(pref2, &nref); | |
79 | pref2 = &nref; | |
80 | break; | |
81 | default: | |
82 | return 0; | |
83 | } | |
84 | } | |
85 | /* Now do a type-dependent comparison. */ | |
86 | /* This would be very simple if we always filled in */ | |
87 | /* all 8 bytes of a ref, but we currently don't. */ | |
88 | switch ( r_btype(pref1) ) | |
89 | { | |
90 | case t_array: | |
91 | return (pref1->value.refs == pref2->value.refs && | |
92 | r_size(pref1) == r_size(pref2)); | |
93 | case t_mixedarray: | |
94 | case t_shortarray: | |
95 | return (pref1->value.packed == pref2->value.packed && | |
96 | r_size(pref1) == r_size(pref2)); | |
97 | case t_boolean: | |
98 | return (pref1->value.index == pref2->value.index); | |
99 | case t_condition: | |
100 | return (pref1->value.pcond == pref2->value.pcond); | |
101 | case t_dictionary: | |
102 | return (pref1->value.pdict == pref2->value.pdict); | |
103 | case t_file: | |
104 | return (pref1->value.pfile == pref2->value.pfile); | |
105 | case t_fontID: | |
106 | return (pref1->value.pfont == pref2->value.pfont); | |
107 | case t_gstate: | |
108 | return (pref1->value.pgstate == pref2->value.pgstate); | |
109 | case t_integer: | |
110 | return (pref1->value.intval == pref2->value.intval); | |
111 | case t_lock: | |
112 | return (pref1->value.plock == pref2->value.plock); | |
113 | case t_mark: | |
114 | case t_null: | |
115 | return 1; | |
116 | case t_name: | |
117 | return (pref1->value.pname == pref2->value.pname); | |
118 | case t_oparray: | |
119 | case t_operator: | |
120 | return (op_index(pref1) == op_index(pref2)); | |
121 | case t_real: | |
122 | return (pref1->value.realval == pref2->value.realval); | |
123 | case t_save: | |
124 | return (pref1->value.psave == pref2->value.psave); | |
125 | case t_string: | |
126 | return (!bytes_compare(pref1->value.bytes, r_size(pref1), | |
127 | pref2->value.bytes, r_size(pref2))); | |
128 | case t_color: | |
129 | { struct gs_color_s | |
130 | *pc1 = pref1->value.pcolor, | |
131 | *pc2 = pref2->value.pcolor; | |
132 | return | |
133 | ( pc1->red == pc2->red && pc1->green == pc2->green && | |
134 | pc1->blue == pc2->blue && pc1->not_black == pc2->not_black | |
135 | ); | |
136 | } | |
137 | case t_device: | |
138 | return (pref1->value.pdevice == pref2->value.pdevice); | |
139 | } | |
140 | return 0; /* shouldn't happen! */ | |
141 | } | |
142 | ||
143 | /* Create a printable representation of an object, a la cvs. */ | |
144 | /* Return 0 if OK, <0 if the destination wasn't large enough. */ | |
145 | int | |
146 | obj_cvs(const ref *op, byte *str, uint len, uint *prlen) | |
147 | { char buf[30]; /* big enough for any float */ | |
148 | byte *pstr = (byte *)buf; | |
149 | uint plen; | |
150 | ref nref; | |
151 | switch ( r_btype(op) ) | |
152 | { | |
153 | case t_boolean: | |
154 | pstr = (byte *)(op->value.index ? "true" : "false"); | |
155 | break; | |
156 | case t_integer: | |
157 | sprintf(buf, "%ld", op->value.intval); | |
158 | break; | |
159 | case t_name: | |
160 | name_string_ref(op, &nref); /* name string */ | |
161 | cvname: pstr = nref.value.bytes; | |
162 | plen = r_size(&nref); | |
163 | goto nl; | |
164 | case t_oparray: | |
165 | name_index_ref(op_array_nx_table[op_index(op) - op_def_count], &nref); | |
166 | name_string_ref(&nref, &nref); | |
167 | goto cvname; | |
168 | case t_operator: | |
169 | { /* Recover the name from the initialization table. */ | |
170 | uint index = op_index(op); | |
171 | if ( index != 0 ) | |
172 | { pstr = (byte *)(op_def_table[index]->oname + 1); | |
173 | break; | |
174 | } | |
175 | } | |
176 | /* Internal operator, no name. */ | |
177 | sprintf(buf, "operator_%lx", (ulong)op->value.opproc); | |
178 | break; | |
179 | case t_real: | |
180 | sprintf(buf, "%g", op->value.realval); | |
181 | break; | |
182 | case t_string: | |
183 | pstr = op->value.bytes; | |
184 | plen = r_size(op); | |
185 | goto nl; | |
186 | default: | |
187 | pstr = (byte *)"--nostringval--"; | |
188 | } | |
189 | plen = strlen((char *)pstr); | |
190 | nl: if ( plen > len ) return e_rangecheck; | |
191 | memcpy(str, pstr, plen); | |
192 | *prlen = plen; | |
193 | return 0; | |
194 | } | |
195 | ||
196 | /* ------ String utilities ------ */ | |
197 | ||
198 | /* Convert a C string to a Ghostscript string */ | |
199 | int | |
200 | string_to_ref(const char *cstr, ref *pref, const char *cname) | |
201 | { uint size = strlen(cstr); | |
202 | char *str = alloc(size, 1, cname); | |
203 | if ( str == 0 ) return e_VMerror; | |
204 | memcpy(str, cstr, size); | |
205 | make_tasv(pref, t_string, a_all, size, bytes, (byte *)str); | |
206 | return 0; | |
207 | } | |
208 | ||
209 | /* Convert a Ghostscript string to a C string. */ | |
210 | /* Return 0 iff the buffer can't be allocated. */ | |
211 | char * | |
212 | ref_to_string(const ref *pref, const char *client_name) | |
213 | { uint size = r_size(pref); | |
214 | char *str = alloc(size + 1, 1, client_name); | |
215 | if ( str == 0 ) return 0; | |
216 | memcpy(str, (char *)pref->value.bytes, size); | |
217 | str[size] = 0; | |
218 | return str; | |
219 | } | |
220 | ||
221 | /* ------ Operand utilities ------ */ | |
222 | ||
223 | /* Get N numeric operands from the stack. */ | |
224 | /* Return a bit-mask indicating which ones are integers, */ | |
225 | /* or a (negative) error indication. */ | |
226 | /* The 1-bit in the bit-mask refers to the bottommost stack entry. */ | |
227 | /* Store float versions of the operands at pval. */ | |
228 | int | |
229 | num_params(const ref *op, int count, float *pval) | |
230 | { int mask = 0; | |
231 | pval += count; | |
232 | while ( --count >= 0 ) | |
233 | { mask <<= 1; | |
234 | switch ( r_type(op) ) | |
235 | { | |
236 | case t_real: | |
237 | *--pval = op->value.realval; | |
238 | break; | |
239 | case t_integer: | |
240 | *--pval = op->value.intval; | |
241 | mask++; | |
242 | break; | |
243 | default: | |
244 | return e_typecheck; | |
245 | } | |
246 | op--; | |
247 | } | |
248 | return mask; | |
249 | } | |
250 | ||
251 | /* Get a real parameter. */ | |
252 | /* If an error is returned, the return value is not updated. */ | |
253 | int | |
254 | real_param(const ref *op, float *pparam) | |
255 | { switch ( r_type(op) ) | |
256 | { | |
257 | case t_integer: *pparam = op->value.intval; break; | |
258 | case t_real: *pparam = op->value.realval; break; | |
259 | default: return e_typecheck; | |
260 | } | |
261 | return 0; | |
262 | } | |
263 | ||
264 | /* ------ Matrix utilities ------ */ | |
265 | ||
266 | /* Check for a matrix operand with read access. */ | |
267 | /* Return 0 if OK, error code if not. */ | |
268 | /* Store an all-float version of the matrix in *pmat. */ | |
269 | int | |
270 | read_matrix(const ref *op, gs_matrix *pmat) | |
271 | { switch ( r_type(op) ) | |
272 | { | |
273 | default: return e_typecheck; | |
274 | case t_array: ; | |
275 | } | |
276 | if ( r_size(op) != 6 ) return e_rangecheck; | |
277 | if ( !r_has_attr(op, a_read) ) return e_invalidaccess; | |
278 | *pmat = *(gs_matrix *)op->value.refs; | |
279 | { ref *pel = (ref *)pmat; | |
280 | int i; | |
281 | for ( i = 0; i < 6; i++ ) | |
282 | { switch ( r_type(pel) ) | |
283 | { | |
284 | default: return e_typecheck; | |
285 | case t_integer: | |
286 | make_real(pel, pel->value.intval); | |
287 | case t_real: ; | |
288 | } | |
289 | pel++; | |
290 | } | |
291 | } | |
292 | return 0; | |
293 | } | |
294 | ||
295 | /* Check for a matrix operand with write access. */ | |
296 | /* Return 0 if OK, error code if not. */ | |
297 | /* Initialize the matrix to an identity matrix */ | |
298 | /* (to set the types and attributes properly.) */ | |
299 | int | |
300 | write_matrix(register ref *op) | |
301 | { ref *aptr; | |
302 | int i; | |
303 | if ( !r_has_type(op, t_array) ) return e_typecheck; | |
304 | if ( !r_has_attr(op, a_write) ) return e_invalidaccess; | |
305 | if ( r_size(op) != 6 ) return e_rangecheck; | |
306 | aptr = op->value.refs; | |
307 | for ( i = 5; i >= 0; i--, aptr++ ) | |
308 | { ref_save(aptr, "write_matrix"); /* we're going to overwrite */ | |
309 | } | |
310 | gs_make_identity((gs_matrix *)op->value.refs); | |
311 | return 0; | |
312 | } |