xref: /plan9/sys/src/cmd/gs/src/gsdparam.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1993, 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: gsdparam.c,v 1.18 2005/06/20 08:59:23 igor Exp $ */
18 /* Default device parameters for Ghostscript library */
19 #include "memory_.h"		/* for memcpy */
20 #include "string_.h"		/* for strlen */
21 #include "gx.h"
22 #include "gserrors.h"
23 #include "gsdevice.h"		/* for prototypes */
24 #include "gsparam.h"
25 #include "gxdevice.h"
26 #include "gxfixed.h"
27 
28 /* Define whether we accept PageSize as a synonym for MediaSize. */
29 /* This is for backward compatibility only. */
30 #define PAGESIZE_IS_MEDIASIZE
31 
32 /* ================ Getting parameters ================ */
33 
34 /* Forward references */
35 private bool param_HWColorMap(gx_device *, byte *);
36 
37 /* Get the device parameters. */
38 int
gs_get_device_or_hw_params(gx_device * orig_dev,gs_param_list * plist,bool is_hardware)39 gs_get_device_or_hw_params(gx_device * orig_dev, gs_param_list * plist,
40 			   bool is_hardware)
41 {
42     /*
43      * We must be prepared to copy the device if it is the read-only
44      * prototype.
45      */
46     gx_device *dev;
47     int code;
48 
49     if (orig_dev->memory)
50 	dev = orig_dev;
51     else {
52 	code = gs_copydevice(&dev, orig_dev, plist->memory);
53 	if (code < 0)
54 	    return code;
55     }
56     gx_device_set_procs(dev);
57     fill_dev_proc(dev, get_params, gx_default_get_params);
58     fill_dev_proc(dev, get_page_device, gx_default_get_page_device);
59     fill_dev_proc(dev, get_alpha_bits, gx_default_get_alpha_bits);
60     code = (is_hardware ?
61 	    (*dev_proc(dev, get_hardware_params)) (dev, plist) :
62 	    (*dev_proc(dev, get_params)) (dev, plist));
63     if (dev != orig_dev)
64 	gx_device_retain(dev, false);  /* frees the copy */
65     return code;
66 }
67 
68 /* Get standard parameters. */
69 int
gx_default_get_params(gx_device * dev,gs_param_list * plist)70 gx_default_get_params(gx_device * dev, gs_param_list * plist)
71 {
72     int code;
73 
74     /* Standard page device parameters: */
75 
76     bool seprs = false;
77     gs_param_string dns, pcms;
78     gs_param_float_array msa, ibba, hwra, ma;
79     gs_param_string_array scna;
80 
81 #define set_param_array(a, d, s)\
82   (a.data = d, a.size = s, a.persistent = false);
83 
84     /* Non-standard parameters: */
85 
86     int colors = dev->color_info.num_components;
87     int mns = colors;
88     int depth = dev->color_info.depth;
89     int GrayValues = dev->color_info.max_gray + 1;
90     int HWSize[2];
91     gs_param_int_array hwsa;
92     gs_param_float_array hwma, mhwra;
93 
94     /* Fill in page device parameters. */
95 
96     param_string_from_string(dns, dev->dname);
97     {
98 	const char *cms = get_process_color_model_name(dev);
99 
100 	/* We might have an uninitialized device with */
101 	/* color_info.num_components = 0.... */
102 	if ((cms != NULL) && (*cms != '\0'))
103 	    param_string_from_string(pcms, cms);
104 	else
105 	    pcms.data = 0;
106     }
107     set_param_array(hwra, dev->HWResolution, 2);
108     set_param_array(msa, dev->MediaSize, 2);
109     set_param_array(ibba, dev->ImagingBBox, 4);
110     set_param_array(ma, dev->Margins, 2);
111     set_param_array(scna, NULL, 0);
112 
113     /* Fill in non-standard parameters. */
114 
115     HWSize[0] = dev->width;
116     HWSize[1] = dev->height;
117     set_param_array(hwsa, HWSize, 2);
118     set_param_array(hwma, dev->HWMargins, 4);
119     set_param_array(mhwra, dev->MarginsHWResolution, 2);
120 
121     /* Transmit the values. */
122 
123     if (
124 
125 	/* Standard parameters */
126 
127 	(code = param_write_name(plist, "OutputDevice", &dns)) < 0 ||
128 #ifdef PAGESIZE_IS_MEDIASIZE
129 	(code = param_write_float_array(plist, "PageSize", &msa)) < 0 ||
130 #endif
131 	(code = (pcms.data == 0 ? 0 :
132 		 param_write_name(plist, "ProcessColorModel", &pcms))) < 0 ||
133 	(code = param_write_float_array(plist, "HWResolution", &hwra)) < 0 ||
134 	(code = (dev->ImagingBBox_set ?
135 		 param_write_float_array(plist, "ImagingBBox", &ibba) :
136 		 param_write_null(plist, "ImagingBBox"))) < 0 ||
137 	(code = param_write_float_array(plist, "Margins", &ma)) < 0 ||
138 	(code = param_write_int(plist, "MaxSeparations", &mns)) < 0 ||
139 	(code = (dev->NumCopies_set < 0 ||
140 		 (*dev_proc(dev, get_page_device))(dev) == 0 ? 0:
141 		 dev->NumCopies_set ?
142 		 param_write_int(plist, "NumCopies", &dev->NumCopies) :
143 		 param_write_null(plist, "NumCopies"))) < 0 ||
144 	(code = param_write_name_array(plist, "SeparationColorNames", &scna)) < 0 ||
145 	(code = param_write_bool(plist, "Separations", &seprs)) < 0 ||
146 	(code = param_write_bool(plist, "UseCIEColor", &dev->UseCIEColor)) < 0 ||
147 
148 	/* Non-standard parameters */
149 
150 	(code = param_write_int_array(plist, "HWSize", &hwsa)) < 0 ||
151 	(code = param_write_float_array(plist, ".HWMargins", &hwma)) < 0 ||
152 	(code = param_write_float_array(plist, ".MarginsHWResolution", &mhwra)) < 0 ||
153 	(code = param_write_float_array(plist, ".MediaSize", &msa)) < 0 ||
154 	(code = param_write_string(plist, "Name", &dns)) < 0 ||
155 	(code = param_write_int(plist, "Colors", &colors)) < 0 ||
156 	(code = param_write_int(plist, "BitsPerPixel", &depth)) < 0 ||
157 	(code = param_write_int(plist, "GrayValues", &GrayValues)) < 0 ||
158 	(code = param_write_long(plist, "PageCount", &dev->PageCount)) < 0 ||
159 	(code = param_write_bool(plist, ".IgnoreNumCopies", &dev->IgnoreNumCopies)) < 0 ||
160 	(code = param_write_int(plist, "TextAlphaBits",
161 				&dev->color_info.anti_alias.text_bits)) < 0 ||
162 	(code = param_write_int(plist, "GraphicsAlphaBits",
163 				&dev->color_info.anti_alias.graphics_bits)) < 0 ||
164 	(code = param_write_bool(plist, ".LockSafetyParams", &dev->LockSafetyParams)) < 0
165 	)
166 	return code;
167 
168     /* Fill in color information. */
169 
170     if (colors > 1) {
171 	int RGBValues = dev->color_info.max_color + 1;
172 	long ColorValues = (depth >= (8 * arch_sizeof_color_index) ? -1
173 							: 1L << depth);
174 
175 	if ((code = param_write_int(plist, "RedValues", &RGBValues)) < 0 ||
176 	    (code = param_write_int(plist, "GreenValues", &RGBValues)) < 0 ||
177 	    (code = param_write_int(plist, "BlueValues", &RGBValues)) < 0 ||
178 	    (code = param_write_long(plist, "ColorValues", &ColorValues)) < 0
179 	    )
180 	    return code;
181     }
182     if (param_requested(plist, "HWColorMap")) {
183 	byte palette[3 << 8];
184 
185 	if (param_HWColorMap(dev, palette)) {
186 	    gs_param_string hwcms;
187 
188 	    hwcms.data = palette, hwcms.size = colors << depth,
189 		hwcms.persistent = false;
190 	    if ((code = param_write_string(plist, "HWColorMap", &hwcms)) < 0)
191 		return code;
192 	}
193     }
194 
195     return 0;
196 }
197 
198 /* Get the color map for a device.  Return true if there is one. */
199 private bool
param_HWColorMap(gx_device * dev,byte * palette)200 param_HWColorMap(gx_device * dev, byte * palette /* 3 << 8 */ )
201 {
202     int depth = dev->color_info.depth;
203     int colors = dev->color_info.num_components;
204 
205     if (depth <= 8 && colors <= 3) {
206 	byte *p = palette;
207 	gx_color_value rgb[3];
208 	gx_color_index i;
209 
210 	fill_dev_proc(dev, map_color_rgb, gx_default_map_color_rgb);
211 	for (i = 0; (i >> depth) == 0; i++) {
212 	    int j;
213 
214 	    if ((*dev_proc(dev, map_color_rgb)) (dev, i, rgb) < 0)
215 		return false;
216 	    for (j = 0; j < colors; j++)
217 		*p++ = gx_color_value_to_byte(rgb[j]);
218 	}
219 	return true;
220     }
221     return false;
222 }
223 
224 /* Get hardware-detected parameters. Default action is no hardware params. */
225 int
gx_default_get_hardware_params(gx_device * dev,gs_param_list * plist)226 gx_default_get_hardware_params(gx_device * dev, gs_param_list * plist)
227 {
228     return 0;
229 }
230 
231 /* ---------------- Input and output media ---------------- */
232 
233 /* Finish defining input or output media. */
234 private int
finish_media(gs_param_list * mlist,gs_param_name key,const char * media_type)235 finish_media(gs_param_list * mlist, gs_param_name key, const char *media_type)
236 {
237     int code = 0;
238 
239     if (media_type != 0) {
240 	gs_param_string as;
241 
242 	param_string_from_string(as, media_type);
243 	code = param_write_string(mlist, key, &as);
244     }
245     return code;
246 }
247 
248 /* Define input media. */
249 
250 const gdev_input_media_t gdev_input_media_default =
251 {
252     gdev_input_media_default_values
253 };
254 
255 int
gdev_begin_input_media(gs_param_list * mlist,gs_param_dict * pdict,int count)256 gdev_begin_input_media(gs_param_list * mlist, gs_param_dict * pdict,
257 		       int count)
258 {
259     pdict->size = count;
260     return param_begin_write_dict(mlist, "InputAttributes", pdict, true);
261 }
262 
263 int
gdev_write_input_media(int index,gs_param_dict * pdict,const gdev_input_media_t * pim)264 gdev_write_input_media(int index, gs_param_dict * pdict,
265 		       const gdev_input_media_t * pim)
266 {
267     char key[25];
268     gs_param_dict mdict;
269     int code;
270     gs_param_string as;
271 
272     sprintf(key, "%d", index);
273     mdict.size = 4;
274     code = param_begin_write_dict(pdict->list, key, &mdict, false);
275     if (code < 0)
276 	return code;
277     if ((pim->PageSize[0] != 0 && pim->PageSize[1] != 0) ||
278 	(pim->PageSize[2] != 0 && pim->PageSize[3] != 0)
279 	) {
280 	gs_param_float_array psa;
281 
282 	psa.data = pim->PageSize;
283 	psa.size =
284 	    (pim->PageSize[0] == pim->PageSize[2] &&
285 	     pim->PageSize[1] == pim->PageSize[3] ? 2 : 4);
286 	psa.persistent = false;
287 	code = param_write_float_array(mdict.list, "PageSize",
288 				       &psa);
289 	if (code < 0)
290 	    return code;
291     }
292     if (pim->MediaColor != 0) {
293 	param_string_from_string(as, pim->MediaColor);
294 	code = param_write_string(mdict.list, "MediaColor",
295 				  &as);
296 	if (code < 0)
297 	    return code;
298     }
299     if (pim->MediaWeight != 0) {
300 	/*
301 	 * We do the following silly thing in order to avoid
302 	 * having to work around the 'const' in the arg list.
303 	 */
304 	float weight = pim->MediaWeight;
305 
306 	code = param_write_float(mdict.list, "MediaWeight",
307 				 &weight);
308 	if (code < 0)
309 	    return code;
310     }
311     code = finish_media(mdict.list, "MediaType", pim->MediaType);
312     if (code < 0)
313 	return code;
314     return param_end_write_dict(pdict->list, key, &mdict);
315 }
316 
317 int
gdev_write_input_page_size(int index,gs_param_dict * pdict,floatp width_points,floatp height_points)318 gdev_write_input_page_size(int index, gs_param_dict * pdict,
319 			   floatp width_points, floatp height_points)
320 {
321     gdev_input_media_t media;
322 
323     media.PageSize[0] = media.PageSize[2] = (float) width_points;
324     media.PageSize[1] = media.PageSize[3] = (float) height_points;
325     media.MediaColor = 0;
326     media.MediaWeight = 0;
327     media.MediaType = 0;
328     return gdev_write_input_media(index, pdict, &media);
329 }
330 
331 int
gdev_end_input_media(gs_param_list * mlist,gs_param_dict * pdict)332 gdev_end_input_media(gs_param_list * mlist, gs_param_dict * pdict)
333 {
334     return param_end_write_dict(mlist, "InputAttributes", pdict);
335 }
336 
337 /* Define output media. */
338 
339 const gdev_output_media_t gdev_output_media_default =
340 {
341     gdev_output_media_default_values
342 };
343 
344 int
gdev_begin_output_media(gs_param_list * mlist,gs_param_dict * pdict,int count)345 gdev_begin_output_media(gs_param_list * mlist, gs_param_dict * pdict,
346 			int count)
347 {
348     pdict->size = count;
349     return param_begin_write_dict(mlist, "OutputAttributes", pdict, true);
350 }
351 
352 int
gdev_write_output_media(int index,gs_param_dict * pdict,const gdev_output_media_t * pom)353 gdev_write_output_media(int index, gs_param_dict * pdict,
354 			const gdev_output_media_t * pom)
355 {
356     char key[25];
357     gs_param_dict mdict;
358     int code;
359 
360     sprintf(key, "%d", index);
361     mdict.size = 4;
362     code = param_begin_write_dict(pdict->list, key, &mdict, false);
363     if (code < 0)
364 	return code;
365     code = finish_media(mdict.list, "OutputType", pom->OutputType);
366     if (code < 0)
367 	return code;
368     return param_end_write_dict(pdict->list, key, &mdict);
369 }
370 
371 int
gdev_end_output_media(gs_param_list * mlist,gs_param_dict * pdict)372 gdev_end_output_media(gs_param_list * mlist, gs_param_dict * pdict)
373 {
374     return param_end_write_dict(mlist, "OutputAttributes", pdict);
375 }
376 
377 /* ================ Putting parameters ================ */
378 
379 /* Forward references */
380 private int param_anti_alias_bits(gs_param_list *, gs_param_name, int *);
381 private int param_MediaSize(gs_param_list *, gs_param_name,
382 			    const float *, gs_param_float_array *);
383 
384 private int param_check_bool(gs_param_list *, gs_param_name, bool, bool);
385 private int param_check_long(gs_param_list *, gs_param_name, long, bool);
386 #define param_check_int(plist, pname, ival, is_defined)\
387   param_check_long(plist, pname, (long)(ival), is_defined)
388 private int param_check_bytes(gs_param_list *, gs_param_name, const byte *,
389 			      uint, bool);
390 #define param_check_string(plist, pname, str, is_defined)\
391   param_check_bytes(plist, pname, (const byte *)(str), \
392                     (is_defined) ? strlen(str) : 0, is_defined)
393 
394 /* Set the device parameters. */
395 /* If the device was open and the put_params procedure closed it, */
396 /* return 1; otherwise, return 0 or an error code as usual. */
397 int
gs_putdeviceparams(gx_device * dev,gs_param_list * plist)398 gs_putdeviceparams(gx_device * dev, gs_param_list * plist)
399 {
400     bool was_open = dev->is_open;
401     int code;
402 
403     gx_device_set_procs(dev);
404     fill_dev_proc(dev, put_params, gx_default_put_params);
405     fill_dev_proc(dev, get_alpha_bits, gx_default_get_alpha_bits);
406     code = (*dev_proc(dev, put_params)) (dev, plist);
407     return (code < 0 ? code : was_open && !dev->is_open ? 1 : code);
408 }
409 
410 /* Set standard parameters. */
411 /* Note that setting the size or resolution closes the device. */
412 /* Window devices that don't want this to happen must temporarily */
413 /* set is_open to false before calling gx_default_put_params, */
414 /* and then taking appropriate action afterwards. */
415 int
gx_default_put_params(gx_device * dev,gs_param_list * plist)416 gx_default_put_params(gx_device * dev, gs_param_list * plist)
417 {
418     int ecode = 0;
419     int code;
420     gs_param_name param_name;
421     gs_param_float_array hwra;
422     gs_param_int_array hwsa;
423     gs_param_float_array msa;
424     gs_param_float_array ma;
425     gs_param_float_array hwma;
426     gs_param_float_array mhwra;
427     gs_param_string_array scna;
428     int nci = dev->NumCopies;
429     int ncset = dev->NumCopies_set;
430     bool ignc = dev->IgnoreNumCopies;
431     bool ucc = dev->UseCIEColor;
432     bool locksafe = dev->LockSafetyParams;
433     gs_param_float_array ibba;
434     bool ibbnull = false;
435     int colors = dev->color_info.num_components;
436     int depth = dev->color_info.depth;
437     int GrayValues = dev->color_info.max_gray + 1;
438     int RGBValues = dev->color_info.max_color + 1;
439     long ColorValues = (depth >= 32 ? -1 : 1L << depth);
440     int tab = dev->color_info.anti_alias.text_bits;
441     int gab = dev->color_info.anti_alias.graphics_bits;
442     gs_param_string cms;
443 
444     /*
445      * Template:
446      *   BEGIN_ARRAY_PARAM(param_read_xxx_array, "pname", pxxa, size, pxxe) {
447      *     ... check value if desired ...
448      *     if (success)
449      *       break;
450      *     ... set ecode ...
451      *   } END_ARRAY_PARAM(pxxa, pxxe);
452      */
453 
454 #define BEGIN_ARRAY_PARAM(pread, pname, pa, psize, e)\
455     BEGIN\
456     switch (code = pread(plist, (param_name = pname), &(pa))) {\
457       case 0:\
458 	if ((pa).size != psize) {\
459 	  ecode = gs_note_error(gs_error_rangecheck);\
460 	  (pa).data = 0;	/* mark as not filled */\
461 	} else
462 #define END_ARRAY_PARAM(pa, e)\
463 	goto e;\
464       default:\
465 	ecode = code;\
466 e:	param_signal_error(plist, param_name, ecode);\
467       case 1:\
468 	(pa).data = 0;		/* mark as not filled */\
469     }\
470     END
471 
472     /*
473      * The HWResolution, HWSize, and MediaSize parameters interact in
474      * the following way:
475      *      1. Setting HWResolution recomputes HWSize from MediaSize.
476      *      2. Setting HWSize recomputes MediaSize from HWResolution.
477      *      3. Setting MediaSize recomputes HWSize from HWResolution.
478      * If more than one parameter is being set, we apply these rules
479      * in the order 1, 2, 3.  This does the right thing in the most
480      * common case of setting more than one parameter, namely,
481      * setting both HWResolution and HWSize.
482      */
483 
484     BEGIN_ARRAY_PARAM(param_read_float_array, "HWResolution", hwra, 2, hwre) {
485 	if (hwra.data[0] <= 0 || hwra.data[1] <= 0)
486 	    ecode = gs_note_error(gs_error_rangecheck);
487 	else
488 	    break;
489     } END_ARRAY_PARAM(hwra, hwre);
490     BEGIN_ARRAY_PARAM(param_read_int_array, "HWSize", hwsa, 2, hwsa) {
491 	/* We need a special check to handle the nullpage device, */
492 	/* whose size is legitimately [0 0]. */
493 	if ((hwsa.data[0] <= 0 && hwsa.data[0] != dev->width) ||
494 	    (hwsa.data[1] <= 0 && hwsa.data[1] != dev->height)
495 	)
496 	    ecode = gs_note_error(gs_error_rangecheck);
497 #define max_coord (max_fixed / fixed_1)
498 #if max_coord < max_int
499 	else if (hwsa.data[0] > max_coord || hwsa.data[1] > max_coord)
500 	    ecode = gs_note_error(gs_error_limitcheck);
501 #endif
502 #undef max_coord
503 	else
504 	    break;
505     } END_ARRAY_PARAM(hwsa, hwse);
506     {
507 	const float *res = (hwra.data == 0 ? dev->HWResolution : hwra.data);
508 
509 #ifdef PAGESIZE_IS_MEDIASIZE
510 	const float *data;
511 
512 	/* .MediaSize takes precedence over PageSize, so */
513 	/* we read PageSize first. */
514 	code = param_MediaSize(plist, "PageSize", res, &msa);
515 	if (code < 0)
516 	    ecode = code;
517 	/* Prevent data from being set to 0 if PageSize is specified */
518 	/* but .MediaSize is not. */
519 	data = msa.data;
520 	code = param_MediaSize(plist, ".MediaSize", res, &msa);
521 	if (code < 0)
522 	    ecode = code;
523 	else if (msa.data == 0)
524 	    msa.data = data;
525 #else
526 	code = param_MediaSize(plist, ".MediaSize", res, &msa);
527 	if (code < 0)
528 	    ecode = code;
529 #endif
530     }
531 
532     BEGIN_ARRAY_PARAM(param_read_float_array, "Margins", ma, 2, me) {
533 	break;
534     } END_ARRAY_PARAM(ma, me);
535     BEGIN_ARRAY_PARAM(param_read_float_array, ".HWMargins", hwma, 4, hwme) {
536 	break;
537     } END_ARRAY_PARAM(hwma, hwme);
538     /* MarginsHWResolution cannot be changed, only checked. */
539     BEGIN_ARRAY_PARAM(param_read_float_array, ".MarginsHWResolution", mhwra, 2, mhwre) {
540 	if (mhwra.data[0] != dev->MarginsHWResolution[0] ||
541 	    mhwra.data[1] != dev->MarginsHWResolution[1]
542 	)
543 	    ecode = gs_note_error(gs_error_rangecheck);
544 	else
545 	    break;
546     } END_ARRAY_PARAM(mhwra, mhwre);
547     switch (code = param_read_bool(plist, (param_name = ".IgnoreNumCopies"), &ignc)) {
548 	default:
549 	    ecode = code;
550 	    param_signal_error(plist, param_name, ecode);
551 	case 0:
552 	case 1:
553 	    break;
554     }
555     if (dev->NumCopies_set >= 0 &&
556 	(*dev_proc(dev, get_page_device))(dev) != 0
557 	) {
558 	switch (code = param_read_int(plist, (param_name = "NumCopies"), &nci)) {
559 	case 0:
560 	    if (nci < 0)
561 		ecode = gs_error_rangecheck;
562 	    else {
563 		ncset = 1;
564 		break;
565 	    }
566 	    goto nce;
567 	default:
568 	    if ((code = param_read_null(plist, param_name)) == 0) {
569 		ncset = 0;
570 		break;
571 	    }
572 	    ecode = code;	/* can't be 1 */
573 nce:
574 	    param_signal_error(plist, param_name, ecode);
575 	case 1:
576 	    break;
577     }
578     }
579     if ((code = param_read_bool(plist, (param_name = "UseCIEColor"), &ucc)) < 0) {
580 	ecode = code;
581 	param_signal_error(plist, param_name, ecode);
582     }
583     if ((code = param_anti_alias_bits(plist, "TextAlphaBits", &tab)) < 0)
584 	ecode = code;
585     if ((code = param_anti_alias_bits(plist, "GraphicsAlphaBits", &gab)) < 0)
586 	ecode = code;
587 
588     switch (code = param_read_bool(plist, (param_name = ".LockSafetyParams"), &locksafe)) {
589 	case 0:
590 	    if (dev->LockSafetyParams && !locksafe)
591 		code = gs_note_error(gs_error_invalidaccess);
592 	    else
593 		break;
594 	default:
595 	    ecode = code;
596 	    param_signal_error(plist, param_name, ecode);
597 	case 1:
598 	    break;
599     }
600     /* Ignore parameters that only have meaning for printers. */
601 #define IGNORE_INT_PARAM(pname)\
602   { int igni;\
603     switch ( code = param_read_int(plist, (param_name = pname), &igni) )\
604       { default:\
605 	  ecode = code;\
606 	  param_signal_error(plist, param_name, ecode);\
607 	case 0:\
608 	case 1:\
609 	  break;\
610       }\
611   }
612     IGNORE_INT_PARAM("%MediaSource")
613 	IGNORE_INT_PARAM("%MediaDestination")
614 	switch (code = param_read_float_array(plist, (param_name = "ImagingBBox"), &ibba)) {
615 	case 0:
616 	    if (ibba.size != 4 ||
617 		ibba.data[2] < ibba.data[0] || ibba.data[3] < ibba.data[1]
618 		)
619 		ecode = gs_note_error(gs_error_rangecheck);
620 	    else
621 		break;
622 	    goto ibbe;
623 	default:
624 	    if ((code = param_read_null(plist, param_name)) == 0) {
625 		ibbnull = true;
626 		ibba.data = 0;
627 		break;
628 	    }
629 	    ecode = code;	/* can't be 1 */
630 	  ibbe:param_signal_error(plist, param_name, ecode);
631 	case 1:
632 	    ibba.data = 0;
633 	    break;
634     }
635 
636     /* Separation, DeviceN Color, and ProcessColorModel related parameters. */
637     {
638 	const char * pcms = get_process_color_model_name(dev);
639         /* the device should have set a process model name at this point */
640 	if ((code = param_check_string(plist, "ProcessColorModel", pcms, (pcms != NULL))) < 0)
641 	    ecode = code;
642     }
643     IGNORE_INT_PARAM("MaxSeparations")
644     if ((code = param_check_bool(plist, "Separations", false, true)) < 0)
645 	ecode = code;
646 
647     BEGIN_ARRAY_PARAM(param_read_name_array, "SeparationColorNames", scna, scna.size, scne) {
648 	break;
649     } END_ARRAY_PARAM(scna, scne);
650 
651 
652     /* Now check nominally read-only parameters. */
653     if ((code = param_check_string(plist, "OutputDevice", dev->dname, true)) < 0)
654 	ecode = code;
655     if ((code = param_check_string(plist, "Name", dev->dname, true)) < 0)
656 	ecode = code;
657     if ((code = param_check_int(plist, "Colors", colors, true)) < 0)
658 	ecode = code;
659     if ((code = param_check_int(plist, "BitsPerPixel", depth, true)) < 0)
660 	ecode = code;
661     if ((code = param_check_int(plist, "GrayValues", GrayValues, true)) < 0)
662 	ecode = code;
663     if ((code = param_check_long(plist, "PageCount", dev->PageCount, true)) < 0)
664 	ecode = code;
665     if ((code = param_check_int(plist, "RedValues", RGBValues, true)) < 0)
666 	ecode = code;
667     if ((code = param_check_int(plist, "GreenValues", RGBValues, true)) < 0)
668 	ecode = code;
669     if ((code = param_check_int(plist, "BlueValues", RGBValues, true)) < 0)
670 	ecode = code;
671     if ((code = param_check_long(plist, "ColorValues", ColorValues, true)) < 0)
672 	ecode = code;
673     if (param_read_string(plist, "HWColorMap", &cms) != 1) {
674 	byte palette[3 << 8];
675 
676 	if (param_HWColorMap(dev, palette))
677 	    code = param_check_bytes(plist, "HWColorMap", palette,
678 				     colors << depth, true);
679 	else
680 	    code = param_check_bytes(plist, "HWColorMap", 0, 0, false);
681 	if (code < 0)
682 	    ecode = code;
683     }
684 
685     /* We must 'commit', in order to detect unknown parameters, */
686     /* even if there were errors. */
687     code = param_commit(plist);
688     if (ecode < 0)
689 	return ecode;
690     if (code < 0)
691 	return code;
692 
693     /* Now actually make the changes. */
694     /* Changing resolution or page size requires closing the device, */
695     /* but changing margins or ImagingBBox does not. */
696     /* In order not to close and reopen the device unnecessarily, */
697     /* we check for replacing the values with the same ones. */
698 
699     if (hwra.data != 0 &&
700 	(dev->HWResolution[0] != hwra.data[0] ||
701 	 dev->HWResolution[1] != hwra.data[1])
702 	) {
703 	if (dev->is_open)
704 	    gs_closedevice(dev);
705 	gx_device_set_resolution(dev, hwra.data[0], hwra.data[1]);
706     }
707     if (hwsa.data != 0 &&
708 	(dev->width != hwsa.data[0] ||
709 	 dev->height != hwsa.data[1])
710 	) {
711 	if (dev->is_open)
712 	    gs_closedevice(dev);
713 	gx_device_set_width_height(dev, hwsa.data[0], hwsa.data[1]);
714     }
715     if (msa.data != 0 &&
716 	(dev->MediaSize[0] != msa.data[0] ||
717 	 dev->MediaSize[1] != msa.data[1])
718 	) {
719 	if (dev->is_open)
720 	    gs_closedevice(dev);
721 	gx_device_set_page_size(dev, msa.data[0], msa.data[1]);
722     }
723     if (ma.data != 0) {
724 	dev->Margins[0] = ma.data[0];
725 	dev->Margins[1] = ma.data[1];
726     }
727     if (hwma.data != 0) {
728 	dev->HWMargins[0] = hwma.data[0];
729 	dev->HWMargins[1] = hwma.data[1];
730 	dev->HWMargins[2] = hwma.data[2];
731 	dev->HWMargins[3] = hwma.data[3];
732     }
733     dev->NumCopies = nci;
734     dev->NumCopies_set = ncset;
735     dev->IgnoreNumCopies = ignc;
736     if (ibba.data != 0) {
737 	dev->ImagingBBox[0] = ibba.data[0];
738 	dev->ImagingBBox[1] = ibba.data[1];
739 	dev->ImagingBBox[2] = ibba.data[2];
740 	dev->ImagingBBox[3] = ibba.data[3];
741 	dev->ImagingBBox_set = true;
742     } else if (ibbnull) {
743 	dev->ImagingBBox_set = false;
744     }
745     dev->UseCIEColor = ucc;
746     dev->color_info.anti_alias.text_bits = tab;
747     dev->color_info.anti_alias.graphics_bits = gab;
748     dev->LockSafetyParams = locksafe;
749     gx_device_decache_colors(dev);
750     return 0;
751 }
752 
753 /* Read TextAlphaBits or GraphicsAlphaBits. */
754 private int
param_anti_alias_bits(gs_param_list * plist,gs_param_name param_name,int * pa)755 param_anti_alias_bits(gs_param_list * plist, gs_param_name param_name, int *pa)
756 {
757     int code = param_read_int(plist, param_name, pa);
758 
759     switch (code) {
760     case 0:
761 	switch (*pa) {
762 	case 1: case 2: case 4:
763 	    return 0;
764 	default:
765 	    code = gs_error_rangecheck;
766 	}
767     default:
768 	param_signal_error(plist, param_name, code);
769     case 1:
770 	;
771     }
772     return code;
773 }
774 
775 
776 /* Read .MediaSize or, if supported as a synonym, PageSize. */
777 private int
param_MediaSize(gs_param_list * plist,gs_param_name pname,const float * res,gs_param_float_array * pa)778 param_MediaSize(gs_param_list * plist, gs_param_name pname,
779 		const float *res, gs_param_float_array * pa)
780 {
781     gs_param_name param_name;
782     int ecode = 0;
783     int code;
784 
785     BEGIN_ARRAY_PARAM(param_read_float_array, pname, *pa, 2, mse) {
786 	float width_new = pa->data[0] * res[0] / 72;
787 	float height_new = pa->data[1] * res[1] / 72;
788 
789 	if (width_new < 0 || height_new < 0)
790 	    ecode = gs_note_error(gs_error_rangecheck);
791 #define max_coord (max_fixed / fixed_1)
792 #if max_coord < max_int
793 	else if (width_new > max_coord || height_new > max_coord)
794 	    ecode = gs_note_error(gs_error_limitcheck);
795 #endif
796 #undef max_coord
797 	else
798 	    break;
799     } END_ARRAY_PARAM(*pa, mse);
800     return ecode;
801 }
802 
803 /* Check that a nominally read-only parameter is being set to */
804 /* its existing value. */
805 private int
param_check_bool(gs_param_list * plist,gs_param_name pname,bool value,bool is_defined)806 param_check_bool(gs_param_list * plist, gs_param_name pname, bool value,
807 		 bool is_defined)
808 {
809     int code;
810     bool new_value;
811 
812     switch (code = param_read_bool(plist, pname, &new_value)) {
813 	case 0:
814 	    if (is_defined && new_value == value)
815 		break;
816 	    code = gs_note_error(gs_error_rangecheck);
817 	    goto e;
818 	default:
819 	    if (param_read_null(plist, pname) == 0)
820 		return 1;
821 	  e:param_signal_error(plist, pname, code);
822 	case 1:
823 	    ;
824     }
825     return code;
826 }
827 private int
param_check_long(gs_param_list * plist,gs_param_name pname,long value,bool is_defined)828 param_check_long(gs_param_list * plist, gs_param_name pname, long value,
829 		 bool is_defined)
830 {
831     int code;
832     long new_value;
833 
834     switch (code = param_read_long(plist, pname, &new_value)) {
835 	case 0:
836 	    if (is_defined && new_value == value)
837 		break;
838 	    code = gs_note_error(gs_error_rangecheck);
839 	    goto e;
840 	default:
841 	    if (param_read_null(plist, pname) == 0)
842 		return 1;
843 	  e:param_signal_error(plist, pname, code);
844 	case 1:
845 	    ;
846     }
847     return code;
848 }
849 private int
param_check_bytes(gs_param_list * plist,gs_param_name pname,const byte * str,uint size,bool is_defined)850 param_check_bytes(gs_param_list * plist, gs_param_name pname, const byte * str,
851 		  uint size, bool is_defined)
852 {
853     int code;
854     gs_param_string new_value;
855 
856     switch (code = param_read_string(plist, pname, &new_value)) {
857 	case 0:
858 	    if (is_defined && new_value.size == size &&
859 		!memcmp((const char *)str, (const char *)new_value.data,
860 			size)
861 		)
862 		break;
863 	    code = gs_note_error(gs_error_rangecheck);
864 	    goto e;
865 	default:
866 	    if (param_read_null(plist, pname) == 0)
867 		return 1;
868 	  e:param_signal_error(plist, pname, code);
869 	case 1:
870 	    ;
871     }
872     return code;
873 }
874