1 /* Copyright (C) 1997, 2000 Aladdin Enterprises. All rights reserved. 2 3 This file is part of AFPL Ghostscript. 4 5 AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author or 6 distributor accepts any responsibility for the consequences of using it, or 7 for whether it serves any particular purpose or works at all, unless he or 8 she says so in writing. Refer to the Aladdin Free Public License (the 9 "License") for full details. 10 11 Every copy of AFPL Ghostscript must include a copy of the License, normally 12 in a plain ASCII text file named PUBLIC. The License grants you the right 13 to copy, modify and redistribute AFPL Ghostscript, but only under certain 14 conditions described in the License. Among other things, the License 15 requires that the copyright notice and this notice be preserved on all 16 copies. 17 */ 18 19 /*$Id: zfunc.c,v 1.6.6.2 2002/01/17 06:57:55 dancoby Exp $ */ 20 /* Generic PostScript language interface to Functions */ 21 #include "memory_.h" 22 #include "ghost.h" 23 #include "oper.h" 24 #include "gscdefs.h" 25 #include "gsfunc.h" 26 #include "gsstruct.h" 27 #include "ialloc.h" 28 #include "idict.h" 29 #include "idparam.h" 30 #include "ifunc.h" 31 #include "store.h" 32 33 /* Define the maximum depth of nesting of subsidiary functions. */ 34 #define MAX_SUB_FUNCTION_DEPTH 3 35 36 /* GC descriptors */ 37 gs_private_st_ptr(st_function_ptr, gs_function_t *, "gs_function_t *", 38 function_ptr_enum_ptrs, function_ptr_reloc_ptrs); 39 gs_private_st_element(st_function_ptr_element, gs_function_t *, 40 "gs_function_t *[]", function_ptr_element_enum_ptrs, 41 function_ptr_element_reloc_ptrs, st_function_ptr); 42 43 /* ------ Operators ------ */ 44 45 /* <dict> .buildfunction <function_struct> */ 46 private int 47 zbuildfunction(i_ctx_t *i_ctx_p) 48 { 49 os_ptr op = osp; 50 gs_function_t *pfn; 51 ref cref; /* closure */ 52 int code; 53 54 code = ialloc_ref_array(&cref, a_executable | a_execute, 2, 55 ".buildfunction"); 56 if (code < 0) 57 return code; 58 code = fn_build_function(i_ctx_p, op, &pfn, imemory); 59 if (code < 0) { 60 ifree_ref_array(&cref, ".buildfunction"); 61 return code; 62 } 63 make_istruct_new(cref.value.refs, a_executable | a_execute, pfn); 64 make_oper_new(cref.value.refs + 1, 0, zexecfunction); 65 ref_assign(op, &cref); 66 return 0; 67 } 68 69 /* <in1> ... <function_struct> %execfunction <out1> ... */ 70 int 71 zexecfunction(i_ctx_t *i_ctx_p) 72 { 73 os_ptr op = osp; 74 75 /* 76 * Since this operator's name begins with %, the name is not defined 77 * in systemdict. The only place this operator can ever appear is 78 * in the execute-only closure created by .buildfunction. 79 * Therefore, in principle it is unnecessary to check the argument. 80 * However, we do a little checking anyway just on general 81 * principles. Note that since the argument may be an instance of 82 * any subclass of gs_function_t, we currently have no way to check 83 * its type. 84 */ 85 if (!r_is_struct(op) || 86 !r_has_masked_attrs(op, a_executable | a_execute, a_executable | a_all) 87 ) 88 return_error(e_typecheck); 89 { 90 gs_function_t *pfn = (gs_function_t *) op->value.pstruct; 91 int m = pfn->params.m, n = pfn->params.n; 92 int diff = n - (m + 1); 93 94 if (diff > 0) 95 check_ostack(diff); 96 { 97 float params[20]; /* arbitrary size, just to avoid allocs */ 98 float *in; 99 float *out; 100 int code = 0; 101 102 if (m + n <= countof(params)) { 103 in = params; 104 } else { 105 in = (float *)ialloc_byte_array(m + n, sizeof(float), 106 "%execfunction(in/out)"); 107 if (in == 0) 108 code = gs_note_error(e_VMerror); 109 } 110 out = in + m; 111 if (code < 0 || 112 (code = float_params(op - 1, m, in)) < 0 || 113 (code = gs_function_evaluate(pfn, in, out)) < 0 114 ) 115 DO_NOTHING; 116 else { 117 if (diff > 0) 118 push(diff); /* can't fail */ 119 else if (diff < 0) { 120 pop(-diff); 121 op = osp; 122 } 123 code = make_floats(op + 1 - n, out, n); 124 } 125 if (in != params) 126 ifree_object(in, "%execfunction(in)"); 127 return code; 128 } 129 } 130 } 131 132 /* ------ Procedures ------ */ 133 134 /* Build a function structure from a PostScript dictionary. */ 135 int 136 fn_build_function(i_ctx_t *i_ctx_p, const ref * op, gs_function_t ** ppfn, gs_memory_t *mem) 137 { 138 return fn_build_sub_function(i_ctx_p, op, ppfn, 0, mem); 139 } 140 int 141 fn_build_sub_function(i_ctx_t *i_ctx_p, const ref * op, gs_function_t ** ppfn, 142 int depth, gs_memory_t *mem) 143 { 144 int code, type, i; 145 gs_function_params_t params; 146 147 if (depth > MAX_SUB_FUNCTION_DEPTH) 148 return_error(e_limitcheck); 149 check_type(*op, t_dictionary); 150 code = dict_int_param(op, "FunctionType", 0, max_int, -1, &type); 151 if (code < 0) 152 return code; 153 for (i = 0; i < build_function_type_table_count; ++i) 154 if (build_function_type_table[i].type == type) 155 break; 156 if (i == build_function_type_table_count) 157 return_error(e_rangecheck); 158 /* Collect parameters common to all function types. */ 159 params.Domain = 0; 160 params.Range = 0; 161 code = fn_build_float_array(op, "Domain", true, true, ¶ms.Domain, mem); 162 if (code < 0) 163 goto fail; 164 params.m = code >> 1; 165 code = fn_build_float_array(op, "Range", false, true, ¶ms.Range, mem); 166 if (code < 0) 167 goto fail; 168 params.n = code >> 1; 169 /* Finish building the function. */ 170 /* If this fails, it will free all the parameters. */ 171 return (*build_function_type_table[i].proc) 172 (i_ctx_p, op, ¶ms, depth + 1, ppfn, mem); 173 fail: 174 gs_free_const_object(mem, params.Range, "Range"); 175 gs_free_const_object(mem, params.Domain, "Domain"); 176 return code; 177 } 178 179 /* Allocate an array of function objects. */ 180 int 181 alloc_function_array(uint count, gs_function_t *** pFunctions, 182 gs_memory_t *mem) 183 { 184 gs_function_t **ptr; 185 186 if (count == 0) 187 return_error(e_rangecheck); 188 ptr = gs_alloc_struct_array(mem, count, gs_function_t *, 189 &st_function_ptr_element, "Functions"); 190 if (ptr == 0) 191 return_error(e_VMerror); 192 memset(ptr, 0, sizeof(*ptr) * count); 193 *pFunctions = ptr; 194 return 0; 195 } 196 197 /* 198 * Collect a heap-allocated array of floats. If the key is missing, set 199 * *pparray = 0 and return 0; otherwise set *pparray and return the number 200 * of elements. Note that 0-length arrays are acceptable, so if the value 201 * returned is 0, the caller must check whether *pparray == 0. 202 */ 203 int 204 fn_build_float_array(const ref * op, const char *kstr, bool required, 205 bool even, const float **pparray, gs_memory_t *mem) 206 { 207 ref *par; 208 int code; 209 210 *pparray = 0; 211 if (dict_find_string(op, kstr, &par) <= 0) 212 return (required ? gs_note_error(e_rangecheck) : 0); 213 if (!r_is_array(par)) 214 return_error(e_typecheck); 215 { 216 uint size = r_size(par); 217 float *ptr = (float *) 218 gs_alloc_byte_array(mem, size, sizeof(float), kstr); 219 220 if (ptr == 0) 221 return_error(e_VMerror); 222 code = dict_float_array_check_param(op, kstr, size, ptr, NULL, 223 0, e_rangecheck); 224 if (code < 0 || (even && (code & 1) != 0)) { 225 gs_free_object(mem, ptr, kstr); 226 return(code < 0 ? code : gs_note_error(e_rangecheck)); 227 } 228 *pparray = ptr; 229 } 230 return code; 231 } 232 233 /* 234 * If a PostScript object is a Function procedure, return the function 235 * object, otherwise return 0. 236 */ 237 gs_function_t * 238 ref_function(const ref *op) 239 { 240 if (r_has_type(op, t_array) && 241 r_has_masked_attrs(op, a_executable | a_execute, 242 a_executable | a_all) && 243 r_size(op) == 2 && 244 r_has_type_attrs(op->value.refs + 1, t_operator, a_executable) && 245 op->value.refs[1].value.opproc == zexecfunction && 246 r_is_struct(op->value.refs) && 247 r_has_masked_attrs(op->value.refs, a_executable | a_execute, 248 a_executable | a_all) 249 ) 250 return (gs_function_t *)op->value.refs->value.pstruct; 251 return 0; 252 } 253 254 /* ------ Initialization procedure ------ */ 255 256 const op_def zfunc_op_defs[] = 257 { 258 {"1.buildfunction", zbuildfunction}, 259 {"1%execfunction", zexecfunction}, 260 op_def_end(0) 261 }; 262