1 /* Copyright (C) 1999, 2000 Aladdin Enterprises. All rights reserved. 2 3 This software is provided AS-IS with no warranty, either express or 4 implied. 5 6 This software is distributed under license and may not be copied, 7 modified or distributed except as expressly authorized under the terms 8 of the license contained in the file LICENSE in this distribution. 9 10 For more information about licensing, please refer to 11 http://www.ghostscript.com/licensing/. For information on 12 commercial licensing, go to http://www.artifex.com/licensing/ or 13 contact Artifex Software, Inc., 101 Lucas Valley Road #110, 14 San Rafael, CA 94903, U.S.A., +1(415)492-9861. 15 */ 16 17 /* $Id: zfunc4.c,v 1.12 2004/08/04 19:36:13 stefan Exp $ */ 18 /* PostScript language support for FunctionType 4 (PS Calculator) Functions */ 19 #include "memory_.h" 20 #include "ghost.h" 21 #include "oper.h" 22 #include "opextern.h" 23 #include "gsfunc.h" 24 #include "gsfunc4.h" 25 #include "gsutil.h" 26 #include "idict.h" 27 #include "ifunc.h" 28 #include "iname.h" 29 #include "dstack.h" 30 #include "ialloc.h" 31 /* 32 * FunctionType 4 functions are not defined in the PostScript language. We 33 * provide support for them because they are needed for PDF 1.3. In 34 * addition to the standard FunctionType, Domain, and Range keys, they have 35 * a Function key whose value is a procedure in a restricted subset of the 36 * PostScript language. Specifically, the procedure must (recursively) 37 * contain only integer, real, Boolean, and procedure constants (only as 38 * literal operands of if and and ifelse), and operators chosen from the set 39 * given below. Note that names other than true and false are not allowed: 40 * the procedure must be 'bound'. 41 * 42 * The following list is taken directly from the PDF 1.3 documentation. 43 */ 44 #define XOP(zfn) int zfn(i_ctx_t *) 45 XOP(zabs); XOP(zand); XOP(zatan); XOP(zbitshift); 46 XOP(zceiling); XOP(zcos); XOP(zcvi); XOP(zcvr); 47 XOP(zdiv); XOP(zexp); XOP(zfloor); XOP(zidiv); 48 XOP(zln); XOP(zlog); XOP(zmod); XOP(zmul); 49 XOP(zneg); XOP(znot); XOP(zor); XOP(zround); 50 XOP(zsin); XOP(zsqrt); XOP(ztruncate); XOP(zxor); 51 XOP(zeq); XOP(zge); XOP(zgt); XOP(zle); XOP(zlt); XOP(zne); 52 XOP(z2copy); 53 #undef XOP 54 typedef struct calc_op_s { 55 op_proc_t proc; 56 gs_PtCr_opcode_t opcode; 57 } calc_op_t; 58 static const calc_op_t calc_ops[] = { 59 60 /* Arithmetic operators */ 61 62 {zabs, PtCr_abs}, 63 {zadd, PtCr_add}, 64 {zand, PtCr_and}, 65 {zatan, PtCr_atan}, 66 {zbitshift, PtCr_bitshift}, 67 {zceiling, PtCr_ceiling}, 68 {zcos, PtCr_cos}, 69 {zcvi, PtCr_cvi}, 70 {zcvr, PtCr_cvr}, 71 {zdiv, PtCr_div}, 72 {zexp, PtCr_exp}, 73 {zfloor, PtCr_floor}, 74 {zidiv, PtCr_idiv}, 75 {zln, PtCr_ln}, 76 {zlog, PtCr_log}, 77 {zmod, PtCr_mod}, 78 {zmul, PtCr_mul}, 79 {zneg, PtCr_neg}, 80 {znot, PtCr_not}, 81 {zor, PtCr_or}, 82 {zround, PtCr_round}, 83 {zsin, PtCr_sin}, 84 {zsqrt, PtCr_sqrt}, 85 {zsub, PtCr_sub}, 86 {ztruncate, PtCr_truncate}, 87 {zxor, PtCr_xor}, 88 89 /* Comparison operators */ 90 91 {zeq, PtCr_eq}, 92 {zge, PtCr_ge}, 93 {zgt, PtCr_gt}, 94 {zle, PtCr_le}, 95 {zlt, PtCr_lt}, 96 {zne, PtCr_ne}, 97 98 /* Stack operators */ 99 100 {zcopy, PtCr_copy}, 101 {z2copy, PtCr_copy}, 102 {zdup, PtCr_dup}, 103 {zexch, PtCr_exch}, 104 {zindex, PtCr_index}, 105 {zpop, PtCr_pop}, 106 {zroll, PtCr_roll} 107 108 /* Special operators */ 109 110 /*{zif, PtCr_if},*/ 111 /*{zifelse, PtCr_ifelse},*/ 112 /*{ztrue, PtCr_true},*/ 113 /*{zfalse, PtCr_false}*/ 114 }; 115 116 /* Fix up an if or ifelse forward reference. */ 117 private void 118 psc_fixup(byte *p, byte *to) 119 { 120 int skip = to - (p + 3); 121 122 p[1] = (byte)(skip >> 8); 123 p[2] = (byte)skip; 124 } 125 126 /* 127 * Check a calculator function for validity, optionally storing its encoded 128 * representation and add the size of the encoded representation to *psize. 129 * Note that we arbitrarily limit the depth of procedure nesting. pref is 130 * known to be a procedure. 131 */ 132 #define MAX_PSC_FUNCTION_NESTING 10 133 private int 134 check_psc_function(i_ctx_t *i_ctx_p, const ref *pref, int depth, byte *ops, int *psize) 135 { 136 long i; 137 uint size = r_size(pref); 138 139 for (i = 0; i < size; ++i) { 140 byte no_ops[1 + max(sizeof(int), sizeof(float))]; 141 byte *p = (ops ? ops + *psize : no_ops); 142 ref elt, elt2, elt3; 143 ref * delp; 144 int code; 145 146 array_get(imemory, pref, i, &elt); 147 switch (r_btype(&elt)) { 148 case t_integer: { 149 int i = elt.value.intval; 150 151 #if ARCH_SIZEOF_INT < ARCH_SIZEOF_LONG 152 if (i != elt.value.intval) /* check for truncation */ 153 return_error(e_rangecheck); 154 #endif 155 if (i == (byte)i) { 156 *p = PtCr_byte; 157 p[1] = (byte)i; 158 *psize += 2; 159 } else { 160 *p = PtCr_int; 161 memcpy(p + 1, &i, sizeof(i)); 162 *psize += 1 + sizeof(int); 163 } 164 break; 165 } 166 case t_real: { 167 float f = elt.value.realval; 168 169 *p = PtCr_float; 170 memcpy(p + 1, &f, sizeof(f)); 171 *psize += 1 + sizeof(float); 172 break; 173 } 174 case t_boolean: 175 *p = (elt.value.boolval ? PtCr_true : PtCr_false); 176 ++*psize; 177 break; 178 case t_name: 179 if (!r_has_attr(&elt, a_executable)) 180 return_error(e_rangecheck); 181 name_string_ref(imemory, &elt, &elt); 182 if (!bytes_compare(elt.value.bytes, r_size(&elt), 183 (const byte *)"true", 4)) { 184 *p = PtCr_true; 185 ++*psize; 186 break; 187 } 188 if (!bytes_compare(elt.value.bytes, r_size(&elt), 189 (const byte *)"false", 5)) { 190 *p = PtCr_false; 191 ++*psize; 192 break; 193 } 194 /* Check if the name is a valid operator in systemdict */ 195 if (dict_find(systemdict, &elt, &delp) <= 0) 196 return_error(e_undefined); 197 if (r_btype(delp) != t_operator) 198 return_error(e_typecheck); 199 if (!r_has_attr(delp, a_executable)) 200 return_error(e_rangecheck); 201 elt = *delp; 202 /* Fall into the operator case */ 203 case t_operator: { 204 int j; 205 206 for (j = 0; j < countof(calc_ops); ++j) 207 if (elt.value.opproc == calc_ops[j].proc) { 208 *p = calc_ops[j].opcode; 209 ++*psize; 210 goto next; 211 } 212 return_error(e_rangecheck); 213 } 214 default: { 215 if (!r_is_proc(&elt)) 216 return_error(e_typecheck); 217 if (depth == MAX_PSC_FUNCTION_NESTING) 218 return_error(e_limitcheck); 219 if ((code = array_get(imemory, pref, ++i, &elt2)) < 0) 220 return code; 221 *psize += 3; 222 code = check_psc_function(i_ctx_p, &elt, depth + 1, ops, psize); 223 if (code < 0) 224 return code; 225 /* Check for {proc} if | {proc1} {proc2} ifelse */ 226 #define R_IS_OPER(pref, proc)\ 227 (r_btype(pref) == t_operator && r_has_attr(pref, a_executable) &&\ 228 (pref)->value.opproc == proc) 229 if (R_IS_OPER(&elt2, zif)) { 230 if (ops) { 231 *p = PtCr_if; 232 psc_fixup(p, ops + *psize); 233 } 234 } else if (!r_is_proc(&elt2)) 235 return_error(e_rangecheck); 236 else if ((code == array_get(imemory, pref, ++i, &elt3)) < 0) 237 return code; 238 else if (R_IS_OPER(&elt3, zifelse)) { 239 if (ops) { 240 *p = PtCr_if; 241 psc_fixup(p, ops + *psize + 3); 242 p = ops + *psize; 243 *p = PtCr_else; 244 } 245 *psize += 3; 246 code = check_psc_function(i_ctx_p, &elt2, depth + 1, ops, psize); 247 if (code < 0) 248 return code; 249 if (ops) 250 psc_fixup(p, ops + *psize); 251 } else 252 return_error(e_rangecheck); 253 #undef R_IS_OPER 254 } 255 } 256 next: 257 DO_NOTHING; 258 } 259 return 0; 260 } 261 #undef MAX_PSC_FUNCTION_NESTING 262 263 /* Check prototype */ 264 build_function_proc(gs_build_function_4); 265 266 /* Finish building a FunctionType 4 (PostScript Calculator) function. */ 267 int 268 gs_build_function_4(i_ctx_t *i_ctx_p, const ref *op, const gs_function_params_t * mnDR, 269 int depth, gs_function_t ** ppfn, gs_memory_t *mem) 270 { 271 gs_function_PtCr_params_t params; 272 ref *proc; 273 int code; 274 byte *ops; 275 int size; 276 277 *(gs_function_params_t *)¶ms = *mnDR; 278 params.ops.data = 0; /* in case of failure */ 279 params.ops.size = 0; /* ditto */ 280 if (dict_find_string(op, "Function", &proc) <= 0) { 281 code = gs_note_error(e_rangecheck); 282 goto fail; 283 } 284 if (!r_is_proc(proc)) { 285 code = gs_note_error(e_typecheck); 286 goto fail; 287 } 288 size = 0; 289 code = check_psc_function(i_ctx_p, proc, 0, NULL, &size); 290 if (code < 0) 291 goto fail; 292 ops = gs_alloc_string(mem, size + 1, "gs_build_function_4(ops)"); 293 if (ops == 0) { 294 code = gs_note_error(e_VMerror); 295 goto fail; 296 } 297 size = 0; 298 check_psc_function(i_ctx_p, proc, 0, ops, &size); /* can't fail */ 299 ops[size] = PtCr_return; 300 params.ops.data = ops; 301 params.ops.size = size + 1; 302 code = gs_function_PtCr_init(ppfn, ¶ms, mem); 303 if (code >= 0) 304 return 0; 305 /* free_params will free the ops string */ 306 fail: 307 gs_function_PtCr_free_params(¶ms, mem); 308 return (code < 0 ? code : gs_note_error(e_rangecheck)); 309 } 310