1 /* Copyright (C) 2001-2019 Artifex Software, Inc. 2 All Rights Reserved. 3 4 This software is provided AS-IS with no warranty, either express or 5 implied. 6 7 This software is distributed under license and may not be copied, 8 modified or distributed except as expressly authorized under the terms 9 of the license contained in the file LICENSE in this distribution. 10 11 Refer to licensing information at http://www.artifex.com or contact 12 Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, 13 CA 94945, U.S.A., +1(415)492-9861, for further information. 14 */ 15 16 17 /* Client interface to parameter dictionaries */ 18 19 #ifndef gsparam_INCLUDED 20 # define gsparam_INCLUDED 21 22 #include "gsstype.h" 23 24 /* 25 * Several interfaces use parameter dictionaries to communicate sets of 26 * (key, value) pairs between a client and an object with complex state. 27 * (Several of these correspond directly to similar interfaces in the 28 * PostScript language.) This file defines the API for parameter dictionaries. 29 */ 30 31 /* ---------------- Generic interfaces ---------------- */ 32 33 /* Define the abstract type for a parameter list. */ 34 typedef struct gs_param_list_s gs_param_list; 35 36 /* Define the type for a parameter key name. */ 37 typedef const char *gs_param_name; 38 39 /* 40 * Parameter values fall into three categories: 41 * - Scalar (null, Boolean, int, long, float); 42 * - Homogenous collection (string/name, int array, float array, 43 * string/name array); 44 * - Heterogenous collection (dictionary, int-keyed dictionary, array). 45 * Each category has its own representation and memory management issues. 46 */ 47 typedef enum { 48 /* Scalar */ 49 gs_param_type_null, gs_param_type_bool, gs_param_type_int, 50 gs_param_type_long, gs_param_type_float, 51 /* Homogenous collection */ 52 gs_param_type_string, gs_param_type_name, 53 gs_param_type_int_array, gs_param_type_float_array, 54 gs_param_type_string_array, gs_param_type_name_array, 55 /* Heterogenous collection */ 56 gs_param_type_dict, gs_param_type_dict_int_keys, gs_param_type_array 57 } gs_param_type; 58 59 /* Define a "don't care" type for reading typed values. */ 60 #define gs_param_type_any ((gs_param_type)-1) 61 62 /* 63 * Define the structures for homogenous collection values 64 * (string/name, integer array, or floating point array). 65 * The size is the number of elements, not the size in bytes. 66 * A value is persistent if it is defined as static const, 67 * or if it is allocated in garbage-collectable space and never freed. 68 */ 69 70 #define _param_array_struct(sname,etype)\ 71 struct sname { const etype *data; uint size; bool persistent; } 72 typedef _param_array_struct(gs_param_int_array_s, int) gs_param_int_array; 73 typedef _param_array_struct(gs_param_float_array_s, float) gs_param_float_array; 74 typedef _param_array_struct(gs_param_string_array_s, gs_param_string) gs_param_string_array; 75 76 #define param_string_from_string(ps, str)\ 77 ((ps).data = (const byte *)(str),\ 78 (ps).size = strlen((const char *)(ps).data),\ 79 (ps).persistent = true) 80 81 #define param_string_from_transient_string(ps, str)\ 82 ((ps).data = (const byte *)(str),\ 83 (ps).size = strlen((const char *)(ps).data),\ 84 (ps).persistent = false) 85 86 /* 87 * Define the structure for heterogenous collection values (dictionaries 88 * and heterogenous arrays). 89 */ 90 typedef struct gs_param_collection_s { 91 gs_param_list *list; 92 uint size; 93 } gs_param_collection; 94 typedef gs_param_collection gs_param_dict; 95 typedef gs_param_collection gs_param_array; 96 97 /* 98 * Define the sizes of the various parameter value types, indexed by type. 99 */ 100 #define GS_PARAM_TYPE_SIZES(dict_size)\ 101 0, sizeof(bool), sizeof(int), sizeof(long), sizeof(float),\ 102 sizeof(gs_param_string), sizeof(gs_param_string),\ 103 sizeof(gs_param_int_array), sizeof(gs_param_float_array),\ 104 sizeof(gs_param_string_array), sizeof(gs_param_string_array),\ 105 (dict_size), (dict_size), (dict_size) 106 /* 107 * Define the sizes of the underlying data types contained in or pointed 108 * to by the various value types. 109 */ 110 #define GS_PARAM_TYPE_BASE_SIZES(dict_elt_size)\ 111 0, sizeof(bool), sizeof(int), sizeof(long), sizeof(float),\ 112 1, 1, sizeof(int), sizeof(float),\ 113 sizeof(gs_param_string), sizeof(gs_param_string),\ 114 (dict_elt_size), (dict_elt_size), (dict_elt_size) 115 116 /* Define tables with 0 for the sizes of the heterogenous collections. */ 117 extern const byte gs_param_type_sizes[]; 118 extern const byte gs_param_type_base_sizes[]; 119 120 /* Define a union capable of holding any parameter value. */ 121 #define GS_PARAM_VALUE_UNION(dict_type)\ 122 bool b;\ 123 int i;\ 124 long l;\ 125 float f;\ 126 gs_param_string s;\ 127 gs_param_string n;\ 128 gs_param_int_array ia;\ 129 gs_param_float_array fa;\ 130 gs_param_string_array sa;\ 131 gs_param_string_array na;\ 132 dict_type d 133 typedef union gs_param_value_s { 134 GS_PARAM_VALUE_UNION(gs_param_collection); 135 } gs_param_value; 136 137 /* 138 * Define a structure containing a dynamically typed value (a value along 139 * with its type). 140 */ 141 typedef struct gs_param_typed_value_s { 142 gs_param_value value; 143 gs_param_type type; 144 } gs_param_typed_value; 145 /* 146 * Garbage collection of gs_param_values depends on the value type and on 147 * the 'd' member of the union. We provide enum_ptrs and reloc_ptrs 148 * procedures that handle all the other cases -- i.e., cases other than 149 * heterogenous collections. 150 */ 151 struct_proc_enum_ptrs(gs_param_typed_value_enum_ptrs); 152 struct_proc_reloc_ptrs(gs_param_typed_value_reloc_ptrs); 153 #define gs_param_typed_value_max_ptrs 1 154 155 /* 156 * Define the representation alternatives for heterogenous collections. 157 * _any must be 0, for Boolean testing. 158 */ 159 typedef enum { 160 161 /* Create or accept a general dictionary. */ 162 163 gs_param_collection_dict_any = 0, 164 165 /* Create a dictionary with integer string keys ("0", "1", ...); */ 166 /* accept a dictionary with integer string keys, or a heterogenous */ 167 /* array. */ 168 169 gs_param_collection_dict_int_keys = 1, 170 171 /* Create an array if possible, otherwise a dictionary with integer */ 172 /* string keys; accept the same types as dict_int_keys. */ 173 174 gs_param_collection_array = 2 175 176 } gs_param_collection_type_t; 177 178 /* 179 * Define the 'policies' for handling out-of-range parameter values. 180 * This is not an enum, because some parameters may recognize other values. 181 */ 182 #define gs_param_policy_signal_error 0 183 #define gs_param_policy_ignore 1 184 #define gs_param_policy_consult_user 2 185 186 /* 187 * Define an enumerator used to iterate through the keys in a list. 188 * 189 * All the members of the union must be used such that memset(0) entire 190 * union means 'beginning of enumeration'. 191 */ 192 typedef union gs_param_enumerator_s { 193 int intval; 194 long longval; 195 void *pvoid; 196 char *pchar; 197 } gs_param_enumerator_t; 198 typedef gs_param_string gs_param_key_t; 199 200 /* 201 * Define the object procedures. Note that the same interface is used 202 * both for getting and for setting parameter values. (This is a bit 203 * of a hack, and we might change it someday.) The procedures return 204 * as follows: 205 * - 'reading' procedures ('put' operations from the client's viewpoint) 206 * return 1 for a missing parameter, 0 for a valid parameter, <0 on error. 207 * - 'writing' procedures ('get' operations from the client's viewpoint) 208 * return 0 or 1 if successful, <0 on error. 209 * 210 * A lazy implementation can use the default procedures for scalar and 211 * homogenous collection types: these just called xmit_typed. 212 */ 213 214 /* 215 * Transmitting variable-size objects requires some extra care. 216 * - When writing an array, string, name, or dictionary, the 217 * implementation (not the client) sets all the fields of the value. 218 * - When reading an array, string, or name, the client must set 219 * all the fields of the value. 220 * - When reading a dictionary, the client must set the size field 221 * before calling begin_write_dict; the implementation of begin_write_dict 222 * allocates the list. 223 */ 224 225 /* 226 * Setting parameters must use a "two-phase commit" policy. Specifically, 227 * any put_params procedure must observe the following discipline: 228 229 1. For each parameter known to the device, ask the parameter list if 230 there is a new value, and if so, make all necessary validity checks. If any 231 check fails, call param_signal_error for that parameter, but continue to 232 check further parameters. Normally, this step should not alter the state of 233 the device; however, if the device allows changing any parameters that are 234 read-only by default (for example, BitsPerPixel or ProcessColorModel), or if 235 it replaces the default put_params behavior for any parameter (for example, 236 if it handles MediaSize or Resolution itself to forestall the normal closing 237 of the device when these are set), step 1 of put_params must change the 238 parameters in the device state, and step 2 must undo the changes if 239 returning an error. 240 241 2. Call the "superclass" put_params routine. For printer devices, 242 this is gdev_prn_put_params; for other devices, it is gx_default_put_params. 243 Note that this must be done even if errors were detected in step 1. If this 244 routine returns an error code, or if step 1 detected an error, undo any 245 changes that step 1 made in the device state, and return the error code. 246 247 3. Install the new parameter values in the device. If necessary, 248 close the device first; a higher-level routine (gs_putdeviceparams) will 249 reopen the device if necessary. 250 251 */ 252 253 typedef struct gs_param_list_procs_s { 254 255 /* Transmit a typed value. */ 256 /* 257 * Note that read/write_typed do a begin_read/write_collection 258 * if the type is one of the heterogenous collection types. 259 * Note also that even for reading, the caller must set pvalue->type 260 * to the desired type or to gs_param_type_any. 261 */ 262 263 #define param_proc_xmit_typed(proc)\ 264 int proc(gs_param_list *, gs_param_name, gs_param_typed_value *) 265 param_proc_xmit_typed((*xmit_typed)); 266 /* See below for param_read_[requested_]typed */ 267 #define param_write_typed(plist, pkey, pvalue)\ 268 (*(plist)->procs->xmit_typed)(plist, pkey, pvalue) 269 270 /* Start transmitting a dictionary or heterogenous value. */ 271 272 #define param_proc_begin_xmit_collection(proc)\ 273 int proc(gs_param_list *, gs_param_name, gs_param_dict *,\ 274 gs_param_collection_type_t) 275 param_proc_begin_xmit_collection((*begin_xmit_collection)); 276 #define param_begin_read_collection(plist, pkey, pvalue, coll_type)\ 277 (*(plist)->procs->begin_xmit_collection)(plist, pkey, pvalue, coll_type) 278 #define param_begin_read_dict(l, k, v, int_keys)\ 279 param_begin_read_collection(l, k, v,\ 280 (int_keys ? gs_param_collection_dict_int_keys :\ 281 gs_param_collection_dict_any)) 282 #define param_begin_write_collection(plist, pkey, pvalue, coll_type)\ 283 (*(plist)->procs->begin_xmit_collection)(plist, pkey, pvalue, coll_type) 284 #define param_begin_write_dict(l, k, v, int_keys)\ 285 param_begin_write_collection(l, k, v,\ 286 (int_keys ? gs_param_collection_dict_int_keys :\ 287 gs_param_collection_dict_any)) 288 289 /* Finish transmitting a collection value. */ 290 291 #define param_proc_end_xmit_collection(proc)\ 292 int proc(gs_param_list *, gs_param_name, gs_param_dict *) 293 param_proc_end_xmit_collection((*end_xmit_collection)); 294 #define param_end_read_collection(plist, pkey, pvalue)\ 295 (*(plist)->procs->end_xmit_collection)(plist, pkey, pvalue) 296 #define param_end_read_dict(l, k, v) param_end_read_collection(l, k, v) 297 #define param_end_write_collection(plist, pkey, pvalue)\ 298 (*(plist)->procs->end_xmit_collection)(plist, pkey, pvalue) 299 #define param_end_write_dict(l, k, v) param_end_write_collection(l, k, v) 300 301 /* 302 * Get the next key in sequence. 303 * (Only used when reading.) 304 * Use param_init_enumerator(...) to reset to first key. 305 */ 306 307 #define param_proc_next_key(proc)\ 308 int proc(gs_param_list *, gs_param_enumerator_t *, gs_param_key_t *) 309 param_proc_next_key((*next_key)); 310 #define param_get_next_key(plist, penum, pkey)\ 311 (*(plist)->procs->next_key)(plist, penum, pkey) 312 313 /* 314 * Request a specific parameter. (Only used when writing, before 315 * writing any values.) If no specific parameters are requested, 316 * param_requested always returns -1; if specific parameters 317 * are requested, param_requested will return 1 for those, 318 * and may return either 0 or 1 for others. 319 */ 320 321 #define param_proc_request(proc)\ 322 int proc(gs_param_list *, gs_param_name) 323 param_proc_request((*request)); 324 325 #define param_request(plist, pkey)\ 326 ((plist)->procs->request(plist, pkey)) 327 328 /* 329 * Determine whether a given key has been requested. (Only used 330 * when writing.) A return value of -1 means that no specific 331 * parameters have been requested; 0 means specific parameters have 332 * been requested, but not this one; 1 means this parameter has 333 * been requested specifically. 334 */ 335 336 #define param_proc_requested(proc)\ 337 int proc(const gs_param_list *, gs_param_name) 338 param_proc_requested((*requested)); 339 #define param_requested(plist, pkey)\ 340 (*(plist)->procs->requested)(plist, pkey) 341 342 /* Get the 'policy' associated with an out-of-range parameter value. */ 343 /* (Only used when reading.) */ 344 345 #define param_proc_get_policy(proc)\ 346 int proc(gs_param_list *, gs_param_name) 347 param_proc_get_policy((*get_policy)); 348 #define param_get_policy(plist, pkey)\ 349 (*(plist)->procs->get_policy)(plist, pkey) 350 351 /* 352 * Signal an error. (Only used when reading.) 353 * The procedure may return a different error code, 354 * or may return 0 indicating that the error is to be ignored. 355 */ 356 357 #define param_proc_signal_error(proc)\ 358 int proc(gs_param_list *, gs_param_name, int) 359 param_proc_signal_error((*signal_error)); 360 #define param_signal_error(plist, pkey, code)\ 361 (*(plist)->procs->signal_error)(plist, pkey, code) 362 #define param_return_error(plist, pkey, code)\ 363 return_error(param_signal_error(plist, pkey, code)) 364 365 /* 366 * "Commit" a set of changes. (Only used when reading.) 367 * This is called at the end of the first phase. 368 */ 369 370 #define param_proc_commit(proc)\ 371 int proc(gs_param_list *) 372 param_proc_commit((*commit)); 373 #define param_commit(plist)\ 374 (*(plist)->procs->commit)(plist) 375 376 } gs_param_list_procs; 377 378 /* Transmit typed parameters. */ 379 int param_read_requested_typed(gs_param_list *, gs_param_name, 380 gs_param_typed_value *); 381 382 #define param_read_typed(plist, pkey, pvalue)\ 383 ((pvalue)->type = gs_param_type_any,\ 384 param_read_requested_typed(plist, pkey, pvalue)) 385 386 /* Transmit parameters of specific types. */ 387 388 /*************** WARNING ******************** 389 * You CANNOT use heap allocated strings as 390 * KEYS in param lists. Keys MUST be string 391 * constants. 392 * String values can be heap allocated by 393 * using param_string_from_transient_string() 394 * rather than param_string_from_string() 395 * 396 ********************************************/ 397 int param_read_null(gs_param_list *, gs_param_name); 398 int param_write_null(gs_param_list *, gs_param_name); 399 int param_read_bool(gs_param_list *, gs_param_name, bool *); 400 int param_write_bool(gs_param_list *, gs_param_name, const bool *); 401 int param_read_int(gs_param_list *, gs_param_name, int *); 402 int param_write_int(gs_param_list *, gs_param_name, const int *); 403 int param_read_long(gs_param_list *, gs_param_name, long *); 404 int param_write_long(gs_param_list *, gs_param_name, const long *); 405 int param_read_float(gs_param_list *, gs_param_name, float *); 406 int param_write_float(gs_param_list *, gs_param_name, const float *); 407 int param_read_string(gs_param_list *, gs_param_name, gs_param_string *); 408 int param_write_string(gs_param_list *, gs_param_name, 409 const gs_param_string *); 410 int param_read_name(gs_param_list *, gs_param_name, gs_param_string *); 411 int param_write_name(gs_param_list *, gs_param_name, 412 const gs_param_string *); 413 int param_read_int_array(gs_param_list *, gs_param_name, 414 gs_param_int_array *); 415 int param_write_int_array(gs_param_list *, gs_param_name, 416 const gs_param_int_array *); 417 int param_write_int_values(gs_param_list *, gs_param_name, 418 const int *, uint, bool); 419 int param_read_float_array(gs_param_list *, gs_param_name, 420 gs_param_float_array *); 421 int param_write_float_array(gs_param_list *, gs_param_name, 422 const gs_param_float_array *); 423 int param_write_float_values(gs_param_list *, gs_param_name, 424 const float *, uint, bool); 425 int param_read_string_array(gs_param_list *, gs_param_name, 426 gs_param_string_array *); 427 int param_write_string_array(gs_param_list *, gs_param_name, 428 const gs_param_string_array *); 429 int param_read_name_array(gs_param_list *, gs_param_name, 430 gs_param_string_array *); 431 int param_write_name_array(gs_param_list *, gs_param_name, 432 const gs_param_string_array *); 433 434 /* 435 * Define an abstract parameter list. Implementations are concrete 436 * subclasses. 437 * 438 * The persisent_keys flag allows for both statically and dynamically 439 * allocated keys. The default is static (the keys are normally C string 440 * literals). 441 */ 442 #define gs_param_list_common\ 443 const gs_param_list_procs *procs;\ 444 gs_memory_t *memory; /* for allocating coerced arrays */\ 445 bool persistent_keys 446 struct gs_param_list_s { 447 gs_param_list_common; 448 }; 449 450 /* Set whether the keys for param_write_XXX are persistent. */ 451 /* VMS limits procedure names to 31 characters. */ 452 #define gs_param_list_set_persistent_keys gs_param_list_set_persist_keys 453 void gs_param_list_set_persistent_keys(gs_param_list *, bool); 454 455 /* Initialize a parameter list key enumerator. */ 456 void param_init_enumerator(gs_param_enumerator_t * penum); 457 458 /* 459 * The following interface provides a convenient way to read and set 460 * collections of parameters of any type other than dictionaries. 461 */ 462 463 typedef struct gs_param_item_s { 464 const char *key; 465 byte /*gs_param_type */ type; 466 short offset; /* offset of value in structure */ 467 } gs_param_item_t; 468 #define gs_param_item_end { 0 } /* list terminator */ 469 /* 470 * Transfer a collection of parameters. 471 * For param_write_items, if a parameter value is equal to the value in 472 * the optional default_obj, the item isn't transferred. 473 */ 474 int gs_param_read_items(gs_param_list * plist, void *obj, 475 const gs_param_item_t * items); 476 int gs_param_write_items(gs_param_list * plist, const void *obj, 477 const void *default_obj, 478 const gs_param_item_t * items); 479 480 /* Internal procedure to initialize the common part of a parameter list. */ 481 void gs_param_list_init(gs_param_list *, const gs_param_list_procs *, 482 gs_memory_t *); 483 484 /* 485 * Internal procedure to read a value, with coercion if requested, needed, 486 * and possible. If mem != 0, we can coerce int arrays to float arrays, and 487 * possibly do other coercions later. 488 */ 489 int param_coerce_typed(gs_param_typed_value * pvalue, 490 gs_param_type req_type, gs_memory_t * mem); 491 492 /* ---------------- Default implementation ---------------- */ 493 494 /* 495 * Provide default generic implementations of param_request and 496 * param_requested. 497 */ 498 param_proc_request(gs_param_request_default); /* does nothing */ 499 param_proc_requested(gs_param_requested_default); /* always returns true */ 500 501 /* 502 * Define a default implementation, intended to be usable easily 503 * from C code. The intended usage pattern is: 504 gs_c_param_list list; 505 [... other code here ...] 506 gs_c_param_list_write(&list, mem); 507 [As many as needed:] 508 code = param_write_XXX(&list, "ParamName", ¶m_value); 509 [Check code for <0] 510 gs_c_param_list_read(&list); 511 code = gs_putdeviceparams(dev, &list); 512 gs_c_param_list_release(&list); 513 [Check code for <0] 514 if ( code == 1 ) 515 { 516 code = (*dev_proc(dev, open_device))(dev); 517 [Check code for <0] 518 } 519 * 520 * This implementation also has the special property that it can forward 521 * unrecognized param_read_ calls to another parameter list, called the 522 * target. This allows constructing incrementally modified parameter lists. 523 * Note that this is only relevant for put_params (reading from the 524 * parameter list). 525 */ 526 527 typedef struct gs_c_param_s gs_c_param; /* opaque here */ 528 typedef struct gs_c_param_list_s { 529 gs_param_list_common; 530 gs_c_param *head; 531 gs_param_list *target; 532 uint count; 533 bool any_requested; 534 gs_param_collection_type_t coll_type; 535 } gs_c_param_list; 536 #define private_st_c_param_list() /* in gsparam.c */\ 537 gs_private_st_ptrs2(st_c_param_list, gs_c_param_list, "c_param_list",\ 538 c_param_list_enum_ptrs, c_param_list_reloc_ptrs, head, target) 539 540 /* Define a GC descriptor for gs_param_string. */ 541 /* This structure descriptor is only for non persistent gs_param_strings. */ 542 #define private_st_gs_param_string() /* in gdevdevn.c */\ 543 gs_private_st_composite(st_gs_param_string, gs_param_string, "gs_param_string",\ 544 param_string_enum_ptrs, param_string_reloc_ptrs) 545 546 /* Set the target of a C parameter list. */ 547 void gs_c_param_list_set_target(gs_c_param_list *, gs_param_list *); 548 549 /* 550 * Clients normally allocate the gs_c_param_list on the stack, but we 551 * provide a procedure for allocating one in memory. 552 */ 553 gs_c_param_list *gs_c_param_list_alloc(gs_memory_t *, client_name_t); 554 void gs_c_param_list_write(gs_c_param_list *, gs_memory_t *); 555 void gs_c_param_list_write_more(gs_c_param_list *); /* switch back to writing, no init */ 556 void gs_c_param_list_read(gs_c_param_list *); /* switch to reading */ 557 void gs_c_param_list_release(gs_c_param_list *); 558 559 #endif /* gsparam_INCLUDED */ 560