| 1 | /* Copyright (C) 1991, 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 | /* zprops.c */ |
| 21 | /* Device property operators */ |
| 22 | #include "memory_.h" |
| 23 | #include "ghost.h" |
| 24 | #include "alloc.h" |
| 25 | #include "dict.h" |
| 26 | #include "errors.h" |
| 27 | #include "oper.h" |
| 28 | #include "name.h" |
| 29 | #include "store.h" |
| 30 | #include "gsprops.h" |
| 31 | #include "gsmatrix.h" /* for gxdevice.h */ |
| 32 | #include "gxdevice.h" |
| 33 | |
| 34 | /* Imported procedures */ |
| 35 | extern int array_get(P3(ref *, long, ref *)); |
| 36 | |
| 37 | /* Forward references */ |
| 38 | private int props_to_stack(P3(gs_prop_item *, os_ptr, int)); |
| 39 | private int props_from_stack(P3(gs_prop_item *, os_ptr, int)); |
| 40 | |
| 41 | /* getdeviceprops */ |
| 42 | int |
| 43 | zgetdeviceprops(os_ptr op) |
| 44 | { gx_device *dev; |
| 45 | gs_prop_item *plist; |
| 46 | int count; |
| 47 | int code; |
| 48 | check_type(*op, t_device); |
| 49 | dev = op->value.pdevice; |
| 50 | count = (*dev->procs->get_props)(dev, NULL); |
| 51 | plist = (gs_prop_item *)alloc(count, sizeof(gs_prop_item), "getdeviceprops"); |
| 52 | if ( plist == 0 ) return_error(e_VMerror); |
| 53 | (*dev->procs->get_props)(dev, plist); |
| 54 | code = props_to_stack(plist, op + 1, count); |
| 55 | alloc_free((char *)plist, count, sizeof(gs_prop_item), "getdeviceprops"); |
| 56 | if ( code >= 0 ) |
| 57 | { make_mark(op); |
| 58 | push(code); |
| 59 | code = 0; |
| 60 | } |
| 61 | return code; |
| 62 | } |
| 63 | |
| 64 | /* putdeviceprops */ |
| 65 | int |
| 66 | zputdeviceprops(os_ptr op) |
| 67 | { gx_device *dev; |
| 68 | gs_prop_item *plist; |
| 69 | os_ptr mp; |
| 70 | int count, acount = 0; |
| 71 | int code; |
| 72 | check_type(*op, t_device); |
| 73 | dev = op->value.pdevice; |
| 74 | for ( mp = op - 1; !r_has_type(mp, t_mark); mp-- ) |
| 75 | { if ( mp <= osbot ) return e_unmatchedmark; |
| 76 | switch ( r_type(mp) ) |
| 77 | { |
| 78 | case t_array: |
| 79 | case t_mixedarray: |
| 80 | case t_shortarray: |
| 81 | acount += r_size(mp); |
| 82 | } |
| 83 | } |
| 84 | count = op - mp - 1; |
| 85 | if ( count & 1 ) return e_rangecheck; |
| 86 | count >>= 1; |
| 87 | plist = (gs_prop_item *)alloc(count + acount, sizeof(gs_prop_item), "putdeviceprops"); |
| 88 | if ( plist == 0 ) return_error(e_VMerror); |
| 89 | code = props_from_stack(plist, mp + 1, count); |
| 90 | if ( code >= 0 ) |
| 91 | code = (*dev->procs->put_props)(dev, plist, count + acount); |
| 92 | alloc_free((char *)plist, count + acount, sizeof(gs_prop_item), "putdeviceprops"); |
| 93 | if ( code >= 0 ) |
| 94 | { *mp = *op; |
| 95 | osp = op = mp; |
| 96 | } |
| 97 | return code; |
| 98 | } |
| 99 | |
| 100 | /* ------ Initialization procedure ------ */ |
| 101 | |
| 102 | op_def zprops_op_defs[] = { |
| 103 | {"1getdeviceprops", zgetdeviceprops}, |
| 104 | {"2putdeviceprops", zputdeviceprops}, |
| 105 | op_def_end(0) |
| 106 | }; |
| 107 | |
| 108 | /* ------ Internal routines ------ */ |
| 109 | |
| 110 | /* Get properties from a property list to the stack. */ |
| 111 | private int |
| 112 | props_to_stack(gs_prop_item *plist, os_ptr op0, int count) |
| 113 | { gs_prop_item *pi; |
| 114 | os_ptr op; |
| 115 | int i; |
| 116 | int code; |
| 117 | for ( op = op0, pi = plist, i = count; i != 0; pi++, i-- ) |
| 118 | { ref value; |
| 119 | const char *nstr = pi->pname; |
| 120 | int nlen = pi->name_size; |
| 121 | if ( nstr == 0 ) continue; /* no name, skip */ |
| 122 | if ( ostop - op < 2 ) return e_stackoverflow; |
| 123 | if ( nlen < 0 ) nlen = strlen(nstr); |
| 124 | code = name_ref((const byte *)nstr, nlen, op, 0); |
| 125 | if ( code < 0 ) return code; |
| 126 | switch ( pi->type ) |
| 127 | { |
| 128 | case (int)prt_int: |
| 129 | make_int(&value, pi->value.i); |
| 130 | break; |
| 131 | case (int)prt_float: |
| 132 | make_real(&value, pi->value.f); |
| 133 | break; |
| 134 | case (int)prt_bool: |
| 135 | make_bool(&value, pi->value.b); |
| 136 | break; |
| 137 | case (int)prt_string: |
| 138 | { ushort size = pi->value.a.size; |
| 139 | char *str; |
| 140 | if ( size == (ushort)(-1) ) |
| 141 | size = strlen(pi->value.a.p.s); |
| 142 | str = alloc(size, 1, "props_to_stack(string)"); |
| 143 | if ( str == 0 ) return e_VMerror; |
| 144 | memcpy(str, pi->value.a.p.s, size); |
| 145 | make_tasv(&value, t_string, a_all, size, bytes, (byte *)str); |
| 146 | } break; |
| 147 | case (int)prt_int_array: |
| 148 | case (int)prt_float_array: |
| 149 | { uint size = pi->value.a.size; |
| 150 | ref *arefs = alloc_refs(size, "props_to_stack(array)"); |
| 151 | uint j; |
| 152 | gs_prop_item *pv = pi->value.a.p.v; |
| 153 | if ( arefs == 0 ) return e_VMerror; |
| 154 | make_tasv_new(&value, t_array, a_all, size, refs, arefs); |
| 155 | for ( j = 0; j < size; j++, arefs++, pv++ ) |
| 156 | if ( pi->type == prt_int_array ) |
| 157 | make_int_new(arefs, pv->value.i); |
| 158 | else |
| 159 | make_real_new(arefs, pv->value.f); |
| 160 | } break; |
| 161 | default: |
| 162 | return e_typecheck; |
| 163 | } |
| 164 | ref_assign(op + 1, &value); |
| 165 | op += 2; |
| 166 | } |
| 167 | return op - op0; |
| 168 | } |
| 169 | |
| 170 | /* Set properties from the stack. */ |
| 171 | /* Returns the number of elements copied. */ |
| 172 | /* Entries with non-name keys are not copied; */ |
| 173 | /* entries with invalid values are copied with status = pv_typecheck. */ |
| 174 | private int |
| 175 | props_from_stack(gs_prop_item *plist /* [count + acount] */, os_ptr op0, |
| 176 | int count) |
| 177 | { gs_prop_item *pi = plist; |
| 178 | gs_prop_item *pai = plist + count; |
| 179 | os_ptr op = op0 + 1; |
| 180 | for ( ; count; op += 2, count-- ) |
| 181 | { ref sref; |
| 182 | if ( !r_has_type(op - 1, t_name) ) return e_typecheck; |
| 183 | name_string_ref(op - 1, &sref); |
| 184 | pi->pname = (char *)sref.value.bytes; |
| 185 | pi->name_size = r_size(&sref); |
| 186 | pi->status = pv_set; |
| 187 | switch ( r_type(op) ) |
| 188 | { |
| 189 | case t_null: |
| 190 | pi->type = prt_null; |
| 191 | break; |
| 192 | case t_integer: |
| 193 | pi->type = prt_int; |
| 194 | pi->value.i = op->value.intval; |
| 195 | break; |
| 196 | case t_real: |
| 197 | pi->type = prt_float; |
| 198 | pi->value.f = op->value.realval; |
| 199 | break; |
| 200 | case t_boolean: |
| 201 | pi->type = prt_bool; |
| 202 | pi->value.b = op->value.index; |
| 203 | break; |
| 204 | case t_name: |
| 205 | name_string_ref(op, &sref); |
| 206 | goto nst; |
| 207 | case t_string: |
| 208 | ref_assign(&sref, op); |
| 209 | pi->type = prt_string; |
| 210 | pi->value.a.p.s = (char *)op->value.bytes; |
| 211 | nst: pi->value.a.size = r_size(&sref); |
| 212 | break; |
| 213 | case t_array: |
| 214 | case t_mixedarray: |
| 215 | case t_shortarray: |
| 216 | { uint size = r_size(op); |
| 217 | uint i; |
| 218 | gs_prop_item *pv; |
| 219 | gs_prop_type tv = prt_int; |
| 220 | pi->type = prt_int_array; |
| 221 | pi->value.a.p.v = pai; |
| 222 | pi->value.a.size = size; |
| 223 | top: pv = pai; |
| 224 | for ( i = 0; i < size; i++ ) |
| 225 | { ref rnum; |
| 226 | array_get(op, (long)i, &rnum); |
| 227 | pv->pname = 0; |
| 228 | pv->type = tv; |
| 229 | switch ( r_type(&rnum) ) |
| 230 | { |
| 231 | case t_real: |
| 232 | if ( tv == prt_int ) |
| 233 | { tv = prt_float; |
| 234 | pi->type = prt_float_array; |
| 235 | goto top; |
| 236 | } |
| 237 | pv++->value.f = rnum.value.realval; |
| 238 | break; |
| 239 | case t_integer: |
| 240 | if ( tv == prt_int ) |
| 241 | pv++->value.i = rnum.value.intval; |
| 242 | else |
| 243 | pv++->value.f = rnum.value.intval; |
| 244 | break; |
| 245 | default: |
| 246 | pi->status = pv_typecheck; |
| 247 | } |
| 248 | } |
| 249 | |
| 250 | pai = pv; |
| 251 | } break; |
| 252 | default: |
| 253 | pi->status = pv_typecheck; |
| 254 | } |
| 255 | pi++; |
| 256 | } |
| 257 | return 0; |
| 258 | } |