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", &param_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