1 /* Copyright (C) 1993, 2000 artofcode LLC.  All rights reserved.
2 
3   This program is free software; you can redistribute it and/or modify it
4   under the terms of the GNU General Public License as published by the
5   Free Software Foundation; either version 2 of the License, or (at your
6   option) any later version.
7 
8   This program is distributed in the hope that it will be useful, but
9   WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   General Public License for more details.
12 
13   You should have received a copy of the GNU General Public License along
14   with this program; if not, write to the Free Software Foundation, Inc.,
15   59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16 
17 */
18 
19 /*$Id: gsdparam.c,v 1.4.6.2.2.1 2003/01/17 00:49:02 giles Exp $ */
20 /* Default device parameters for Ghostscript library */
21 #include "memory_.h"		/* for memcpy */
22 #include "string_.h"		/* for strlen */
23 #include "gx.h"
24 #include "gserrors.h"
25 #include "gsdevice.h"		/* for prototypes */
26 #include "gsparam.h"
27 #include "gxdevice.h"
28 #include "gxfixed.h"
29 
30 /* Define whether we accept PageSize as a synonym for MediaSize. */
31 /* This is for backward compatibility only. */
32 #define PAGESIZE_IS_MEDIASIZE
33 
34 /* ================ Getting parameters ================ */
35 
36 /* Forward references */
37 private bool param_HWColorMap(P2(gx_device *, byte *));
38 
39 /* Get the device parameters. */
40 int
gs_get_device_or_hw_params(gx_device * orig_dev,gs_param_list * plist,bool is_hardware)41 gs_get_device_or_hw_params(gx_device * orig_dev, gs_param_list * plist,
42 			   bool is_hardware)
43 {
44     /*
45      * We must be prepared to copy the device if it is the read-only
46      * prototype.
47      */
48     gx_device *dev;
49     int code;
50 
51     if (orig_dev->memory)
52 	dev = orig_dev;
53     else {
54 	code = gs_copydevice(&dev, orig_dev, plist->memory);
55 	if (code < 0)
56 	    return code;
57     }
58     gx_device_set_procs(dev);
59     fill_dev_proc(dev, get_params, gx_default_get_params);
60     fill_dev_proc(dev, get_page_device, gx_default_get_page_device);
61     fill_dev_proc(dev, get_alpha_bits, gx_default_get_alpha_bits);
62     code = (is_hardware ?
63 	    (*dev_proc(dev, get_hardware_params)) (dev, plist) :
64 	    (*dev_proc(dev, get_params)) (dev, plist));
65     if (dev != orig_dev)
66 	gx_device_retain(dev, false);  /* frees the copy */
67     return code;
68 }
69 
70 /* Standard ProcessColorModel values. */
71 static const char *const pcmsa[] =
72 {
73     "", "DeviceGray", "", "DeviceRGB", "DeviceCMYK"
74 };
75 
76 /* Get standard parameters. */
77 int
gx_default_get_params(gx_device * dev,gs_param_list * plist)78 gx_default_get_params(gx_device * dev, gs_param_list * plist)
79 {
80     int code;
81 
82     /* Standard page device parameters: */
83 
84     int mns = 1;
85     bool seprs = false;
86     gs_param_string dns, pcms;
87     gs_param_float_array msa, ibba, hwra, ma;
88     gs_param_string_array scna;
89 
90 #define set_param_array(a, d, s)\
91   (a.data = d, a.size = s, a.persistent = false);
92 
93     /* Non-standard parameters: */
94 
95     int colors = dev->color_info.num_components;
96     int depth = dev->color_info.depth;
97     int GrayValues = dev->color_info.max_gray + 1;
98     int HWSize[2];
99     gs_param_int_array hwsa;
100     gs_param_float_array hwma, mhwra;
101 
102     /* Fill in page device parameters. */
103 
104     param_string_from_string(dns, dev->dname);
105     {
106 	const char *cms = pcmsa[colors];
107 
108 	/* We might have an uninitialized device with */
109 	/* color_info.num_components = 0.... */
110 	if (*cms != 0)
111 	    param_string_from_string(pcms, cms);
112 	else
113 	    pcms.data = 0;
114     }
115     set_param_array(hwra, dev->HWResolution, 2);
116     set_param_array(msa, dev->MediaSize, 2);
117     set_param_array(ibba, dev->ImagingBBox, 4);
118     set_param_array(ma, dev->Margins, 2);
119     set_param_array(scna, NULL, 0);
120 
121     /* Fill in non-standard parameters. */
122 
123     HWSize[0] = dev->width;
124     HWSize[1] = dev->height;
125     set_param_array(hwsa, HWSize, 2);
126     set_param_array(hwma, dev->HWMargins, 4);
127     set_param_array(mhwra, dev->MarginsHWResolution, 2);
128 
129     /* Transmit the values. */
130 
131     if (
132 
133 	/* Standard parameters */
134 
135 	(code = param_write_name(plist, "OutputDevice", &dns)) < 0 ||
136 #ifdef PAGESIZE_IS_MEDIASIZE
137 	(code = param_write_float_array(plist, "PageSize", &msa)) < 0 ||
138 #endif
139 	(code = (pcms.data == 0 ? 0 :
140 		 param_write_name(plist, "ProcessColorModel", &pcms))) < 0 ||
141 	(code = param_write_float_array(plist, "HWResolution", &hwra)) < 0 ||
142 	(code = (dev->ImagingBBox_set ?
143 		 param_write_float_array(plist, "ImagingBBox", &ibba) :
144 		 param_write_null(plist, "ImagingBBox"))) < 0 ||
145 	(code = param_write_float_array(plist, "Margins", &ma)) < 0 ||
146 	(code = param_write_int(plist, "MaxSeparations", &mns)) < 0 ||
147 	(code = (dev->NumCopies_set < 0 ||
148 		 (*dev_proc(dev, get_page_device))(dev) == 0 ? 0:
149 		 dev->NumCopies_set ?
150 		 param_write_int(plist, "NumCopies", &dev->NumCopies) :
151 		 param_write_null(plist, "NumCopies"))) < 0 ||
152 	(code = param_write_name_array(plist, "SeparationColorNames", &scna)) < 0 ||
153 	(code = param_write_bool(plist, "Separations", &seprs)) < 0 ||
154 	(code = param_write_bool(plist, "UseCIEColor", &dev->UseCIEColor)) < 0 ||
155 
156 	/* Non-standard parameters */
157 
158 	(code = param_write_int_array(plist, "HWSize", &hwsa)) < 0 ||
159 	(code = param_write_float_array(plist, ".HWMargins", &hwma)) < 0 ||
160 	(code = param_write_float_array(plist, ".MarginsHWResolution", &mhwra)) < 0 ||
161 	(code = param_write_float_array(plist, ".MediaSize", &msa)) < 0 ||
162 	(code = param_write_string(plist, "Name", &dns)) < 0 ||
163 	(code = param_write_int(plist, "Colors", &colors)) < 0 ||
164 	(code = param_write_int(plist, "BitsPerPixel", &depth)) < 0 ||
165 	(code = param_write_int(plist, "GrayValues", &GrayValues)) < 0 ||
166 	(code = param_write_long(plist, "PageCount", &dev->PageCount)) < 0 ||
167 	(code = param_write_bool(plist, ".IgnoreNumCopies", &dev->IgnoreNumCopies)) < 0 ||
168 	(code = param_write_int(plist, "TextAlphaBits",
169 				&dev->color_info.anti_alias.text_bits)) < 0 ||
170 	(code = param_write_int(plist, "GraphicsAlphaBits",
171 				&dev->color_info.anti_alias.graphics_bits)) < 0 ||
172 	(code = param_write_bool(plist, ".LockSafetyParams", &dev->LockSafetyParams)) < 0
173 	)
174 	return code;
175 
176     /* Fill in color information. */
177 
178     if (colors > 1) {
179 	int RGBValues = dev->color_info.max_color + 1;
180 	long ColorValues = 1L << depth;
181 
182 	if ((code = param_write_int(plist, "RedValues", &RGBValues)) < 0 ||
183 	    (code = param_write_int(plist, "GreenValues", &RGBValues)) < 0 ||
184 	    (code = param_write_int(plist, "BlueValues", &RGBValues)) < 0 ||
185 	    (code = param_write_long(plist, "ColorValues", &ColorValues)) < 0
186 	    )
187 	    return code;
188     }
189     if (param_requested(plist, "HWColorMap")) {
190 	byte palette[3 << 8];
191 
192 	if (param_HWColorMap(dev, palette)) {
193 	    gs_param_string hwcms;
194 
195 	    hwcms.data = palette, hwcms.size = colors << depth,
196 		hwcms.persistent = false;
197 	    if ((code = param_write_string(plist, "HWColorMap", &hwcms)) < 0)
198 		return code;
199 	}
200     }
201 
202     return 0;
203 }
204 
205 /* Get the color map for a device.  Return true if there is one. */
206 private bool
param_HWColorMap(gx_device * dev,byte * palette)207 param_HWColorMap(gx_device * dev, byte * palette /* 3 << 8 */ )
208 {
209     int depth = dev->color_info.depth;
210     int colors = dev->color_info.num_components;
211 
212     if (depth <= 8 && colors <= 3) {
213 	byte *p = palette;
214 	gx_color_value rgb[3];
215 	gx_color_index i;
216 
217 	fill_dev_proc(dev, map_color_rgb, gx_default_map_color_rgb);
218 	for (i = 0; (i >> depth) == 0; i++) {
219 	    int j;
220 
221 	    if ((*dev_proc(dev, map_color_rgb)) (dev, i, rgb) < 0)
222 		return false;
223 	    for (j = 0; j < colors; j++)
224 		*p++ = gx_color_value_to_byte(rgb[j]);
225 	}
226 	return true;
227     }
228     return false;
229 }
230 
231 /* Get hardware-detected parameters. Default action is no hardware params. */
232 int
gx_default_get_hardware_params(gx_device * dev,gs_param_list * plist)233 gx_default_get_hardware_params(gx_device * dev, gs_param_list * plist)
234 {
235     return 0;
236 }
237 
238 /* ---------------- Input and output media ---------------- */
239 
240 /* Finish defining input or output media. */
241 private int
finish_media(gs_param_list * mlist,gs_param_name key,const char * media_type)242 finish_media(gs_param_list * mlist, gs_param_name key, const char *media_type)
243 {
244     int code = 0;
245 
246     if (media_type != 0) {
247 	gs_param_string as;
248 
249 	param_string_from_string(as, media_type);
250 	code = param_write_string(mlist, key, &as);
251     }
252     return code;
253 }
254 
255 /* Define input media. */
256 
257 const gdev_input_media_t gdev_input_media_default =
258 {
259     gdev_input_media_default_values
260 };
261 
262 int
gdev_begin_input_media(gs_param_list * mlist,gs_param_dict * pdict,int count)263 gdev_begin_input_media(gs_param_list * mlist, gs_param_dict * pdict,
264 		       int count)
265 {
266     pdict->size = count;
267     return param_begin_write_dict(mlist, "InputAttributes", pdict, true);
268 }
269 
270 int
gdev_write_input_media(int index,gs_param_dict * pdict,const gdev_input_media_t * pim)271 gdev_write_input_media(int index, gs_param_dict * pdict,
272 		       const gdev_input_media_t * pim)
273 {
274     char key[25];
275     gs_param_dict mdict;
276     int code;
277     gs_param_string as;
278 
279     sprintf(key, "%d", index);
280     mdict.size = 4;
281     code = param_begin_write_dict(pdict->list, key, &mdict, false);
282     if (code < 0)
283 	return code;
284     if ((pim->PageSize[0] != 0 && pim->PageSize[1] != 0) ||
285 	(pim->PageSize[2] != 0 && pim->PageSize[3] != 0)
286 	) {
287 	gs_param_float_array psa;
288 
289 	psa.data = pim->PageSize;
290 	psa.size =
291 	    (pim->PageSize[0] == pim->PageSize[2] &&
292 	     pim->PageSize[1] == pim->PageSize[3] ? 2 : 4);
293 	psa.persistent = false;
294 	code = param_write_float_array(mdict.list, "PageSize",
295 				       &psa);
296 	if (code < 0)
297 	    return code;
298     }
299     if (pim->MediaColor != 0) {
300 	param_string_from_string(as, pim->MediaColor);
301 	code = param_write_string(mdict.list, "MediaColor",
302 				  &as);
303 	if (code < 0)
304 	    return code;
305     }
306     if (pim->MediaWeight != 0) {
307 	/*
308 	 * We do the following silly thing in order to avoid
309 	 * having to work around the 'const' in the arg list.
310 	 */
311 	float weight = pim->MediaWeight;
312 
313 	code = param_write_float(mdict.list, "MediaWeight",
314 				 &weight);
315 	if (code < 0)
316 	    return code;
317     }
318     code = finish_media(mdict.list, "MediaType", pim->MediaType);
319     if (code < 0)
320 	return code;
321     return param_end_write_dict(pdict->list, key, &mdict);
322 }
323 
324 int
gdev_write_input_page_size(int index,gs_param_dict * pdict,floatp width_points,floatp height_points)325 gdev_write_input_page_size(int index, gs_param_dict * pdict,
326 			   floatp width_points, floatp height_points)
327 {
328     gdev_input_media_t media;
329 
330     media.PageSize[0] = media.PageSize[2] = width_points;
331     media.PageSize[1] = media.PageSize[3] = height_points;
332     media.MediaColor = 0;
333     media.MediaWeight = 0;
334     media.MediaType = 0;
335     return gdev_write_input_media(index, pdict, &media);
336 }
337 
338 int
gdev_end_input_media(gs_param_list * mlist,gs_param_dict * pdict)339 gdev_end_input_media(gs_param_list * mlist, gs_param_dict * pdict)
340 {
341     return param_end_write_dict(mlist, "InputAttributes", pdict);
342 }
343 
344 /* Define output media. */
345 
346 const gdev_output_media_t gdev_output_media_default =
347 {
348     gdev_output_media_default_values
349 };
350 
351 int
gdev_begin_output_media(gs_param_list * mlist,gs_param_dict * pdict,int count)352 gdev_begin_output_media(gs_param_list * mlist, gs_param_dict * pdict,
353 			int count)
354 {
355     pdict->size = count;
356     return param_begin_write_dict(mlist, "OutputAttributes", pdict, true);
357 }
358 
359 int
gdev_write_output_media(int index,gs_param_dict * pdict,const gdev_output_media_t * pom)360 gdev_write_output_media(int index, gs_param_dict * pdict,
361 			const gdev_output_media_t * pom)
362 {
363     char key[25];
364     gs_param_dict mdict;
365     int code;
366 
367     sprintf(key, "%d", index);
368     mdict.size = 4;
369     code = param_begin_write_dict(pdict->list, key, &mdict, false);
370     if (code < 0)
371 	return code;
372     code = finish_media(mdict.list, "OutputType", pom->OutputType);
373     if (code < 0)
374 	return code;
375     return param_end_write_dict(pdict->list, key, &mdict);
376 }
377 
378 int
gdev_end_output_media(gs_param_list * mlist,gs_param_dict * pdict)379 gdev_end_output_media(gs_param_list * mlist, gs_param_dict * pdict)
380 {
381     return param_end_write_dict(mlist, "OutputAttributes", pdict);
382 }
383 
384 /* ================ Putting parameters ================ */
385 
386 /* Forward references */
387 private int param_anti_alias_bits(P3(gs_param_list *, gs_param_name, int *));
388 private int param_MediaSize(P4(gs_param_list *, gs_param_name,
389 			       const float *, gs_param_float_array *));
390 
391 private int param_check_bool(P4(gs_param_list *, gs_param_name, bool, bool));
392 private int param_check_long(P4(gs_param_list *, gs_param_name, long, bool));
393 
394 #define param_check_int(plist, pname, ival, defined)\
395   param_check_long(plist, pname, (long)(ival), defined)
396 private int param_check_bytes(P5(gs_param_list *, gs_param_name, const byte *, uint, bool));
397 
398 #define param_check_string(plist, pname, str, defined)\
399   param_check_bytes(plist, pname, (const byte *)str, strlen(str), defined)
400 
401 /* Set the device parameters. */
402 /* If the device was open and the put_params procedure closed it, */
403 /* return 1; otherwise, return 0 or an error code as usual. */
404 int
gs_putdeviceparams(gx_device * dev,gs_param_list * plist)405 gs_putdeviceparams(gx_device * dev, gs_param_list * plist)
406 {
407     bool was_open = dev->is_open;
408     int code;
409 
410     gx_device_set_procs(dev);
411     fill_dev_proc(dev, put_params, gx_default_put_params);
412     fill_dev_proc(dev, get_alpha_bits, gx_default_get_alpha_bits);
413     code = (*dev_proc(dev, put_params)) (dev, plist);
414     return (code < 0 ? code : was_open && !dev->is_open ? 1 : code);
415 }
416 
417 /* Set standard parameters. */
418 /* Note that setting the size or resolution closes the device. */
419 /* Window devices that don't want this to happen must temporarily */
420 /* set is_open to false before calling gx_default_put_params, */
421 /* and then taking appropriate action afterwards. */
422 int
gx_default_put_params(gx_device * dev,gs_param_list * plist)423 gx_default_put_params(gx_device * dev, gs_param_list * plist)
424 {
425     int ecode = 0;
426     int code;
427     gs_param_name param_name;
428     gs_param_float_array hwra;
429     gs_param_int_array hwsa;
430     gs_param_float_array msa;
431     gs_param_float_array ma;
432     gs_param_float_array hwma;
433     gs_param_float_array mhwra;
434     gs_param_string_array scna;
435     int nci = dev->NumCopies;
436     int ncset = dev->NumCopies_set;
437     bool ignc = dev->IgnoreNumCopies;
438     bool ucc = dev->UseCIEColor;
439     bool locksafe = dev->LockSafetyParams;
440     gs_param_float_array ibba;
441     bool ibbnull = false;
442     int colors = dev->color_info.num_components;
443     int depth = dev->color_info.depth;
444     int GrayValues = dev->color_info.max_gray + 1;
445     int RGBValues = dev->color_info.max_color + 1;
446     long ColorValues = 1L << depth;
447     int tab = dev->color_info.anti_alias.text_bits;
448     int gab = dev->color_info.anti_alias.graphics_bits;
449     gs_param_string cms;
450 
451     /*
452      * Template:
453      *   BEGIN_ARRAY_PARAM(param_read_xxx_array, "pname", pxxa, size, pxxe) {
454      *     ... check value if desired ...
455      *     if (success)
456      *       break;
457      *     ... set ecode ...
458      *   } END_ARRAY_PARAM(pxxa, pxxe);
459      */
460 
461 #define BEGIN_ARRAY_PARAM(pread, pname, pa, psize, e)\
462     BEGIN\
463     switch (code = pread(plist, (param_name = pname), &(pa))) {\
464       case 0:\
465 	if ((pa).size != psize) {\
466 	  ecode = gs_note_error(gs_error_rangecheck);\
467 	  (pa).data = 0;	/* mark as not filled */\
468 	} else
469 #define END_ARRAY_PARAM(pa, e)\
470 	goto e;\
471       default:\
472 	ecode = code;\
473 e:	param_signal_error(plist, param_name, ecode);\
474       case 1:\
475 	(pa).data = 0;		/* mark as not filled */\
476     }\
477     END
478 
479     /*
480      * The HWResolution, HWSize, and MediaSize parameters interact in
481      * the following way:
482      *      1. Setting HWResolution recomputes HWSize from MediaSize.
483      *      2. Setting HWSize recomputes MediaSize from HWResolution.
484      *      3. Setting MediaSize recomputes HWSize from HWResolution.
485      * If more than one parameter is being set, we apply these rules
486      * in the order 1, 2, 3.  This does the right thing in the most
487      * common case of setting more than one parameter, namely,
488      * setting both HWResolution and HWSize.
489      */
490 
491     BEGIN_ARRAY_PARAM(param_read_float_array, "HWResolution", hwra, 2, hwre) {
492 	if (hwra.data[0] <= 0 || hwra.data[1] <= 0)
493 	    ecode = gs_note_error(gs_error_rangecheck);
494 	else
495 	    break;
496     } END_ARRAY_PARAM(hwra, hwre);
497     BEGIN_ARRAY_PARAM(param_read_int_array, "HWSize", hwsa, 2, hwsa) {
498 	/* We need a special check to handle the nullpage device, */
499 	/* whose size is legitimately [0 0]. */
500 	if ((hwsa.data[0] <= 0 && hwsa.data[0] != dev->width) ||
501 	    (hwsa.data[1] <= 0 && hwsa.data[1] != dev->height)
502 	)
503 	    ecode = gs_note_error(gs_error_rangecheck);
504 #define max_coord (max_fixed / fixed_1)
505 #if max_coord < max_int
506 	else if (hwsa.data[0] > max_coord || hwsa.data[1] > max_coord)
507 	    ecode = gs_note_error(gs_error_limitcheck);
508 #endif
509 #undef max_coord
510 	else
511 	    break;
512     } END_ARRAY_PARAM(hwsa, hwse);
513     {
514 	const float *res = (hwra.data == 0 ? dev->HWResolution : hwra.data);
515 
516 #ifdef PAGESIZE_IS_MEDIASIZE
517 	const float *data;
518 
519 	/* .MediaSize takes precedence over PageSize, so */
520 	/* we read PageSize first. */
521 	code = param_MediaSize(plist, "PageSize", res, &msa);
522 	if (code < 0)
523 	    ecode = code;
524 	/* Prevent data from being set to 0 if PageSize is specified */
525 	/* but .MediaSize is not. */
526 	data = msa.data;
527 	code = param_MediaSize(plist, ".MediaSize", res, &msa);
528 	if (code < 0)
529 	    ecode = code;
530 	else if (msa.data == 0)
531 	    msa.data = data;
532 #else
533 	code = param_MediaSize(plist, ".MediaSize", res, &msa);
534 	if (code < 0)
535 	    ecode = code;
536 #endif
537     }
538 
539     BEGIN_ARRAY_PARAM(param_read_float_array, "Margins", ma, 2, me) {
540 	break;
541     } END_ARRAY_PARAM(ma, me);
542     BEGIN_ARRAY_PARAM(param_read_float_array, ".HWMargins", hwma, 4, hwme) {
543 	break;
544     } END_ARRAY_PARAM(hwma, hwme);
545     /* MarginsHWResolution cannot be changed, only checked. */
546     BEGIN_ARRAY_PARAM(param_read_float_array, ".MarginsHWResolution", mhwra, 2, mhwre) {
547 	if (mhwra.data[0] != dev->MarginsHWResolution[0] ||
548 	    mhwra.data[1] != dev->MarginsHWResolution[1]
549 	)
550 	    ecode = gs_note_error(gs_error_rangecheck);
551 	else
552 	    break;
553     } END_ARRAY_PARAM(mhwra, mhwre);
554     switch (code = param_read_bool(plist, (param_name = ".IgnoreNumCopies"), &ignc)) {
555 	default:
556 	    ecode = code;
557 	    param_signal_error(plist, param_name, ecode);
558 	case 0:
559 	case 1:
560 	    break;
561     }
562     if (dev->NumCopies_set >= 0 &&
563 	(*dev_proc(dev, get_page_device))(dev) != 0
564 	) {
565 	switch (code = param_read_int(plist, (param_name = "NumCopies"), &nci)) {
566 	case 0:
567 	    if (nci < 0)
568 		ecode = gs_error_rangecheck;
569 	    else {
570 		ncset = 1;
571 		break;
572 	    }
573 	    goto nce;
574 	default:
575 	    if ((code = param_read_null(plist, param_name)) == 0) {
576 		ncset = 0;
577 		break;
578 	    }
579 	    ecode = code;	/* can't be 1 */
580 nce:
581 	    param_signal_error(plist, param_name, ecode);
582 	case 1:
583 	    break;
584     }
585     }
586     if ((code = param_read_bool(plist, (param_name = "UseCIEColor"), &ucc)) < 0) {
587 	ecode = code;
588 	param_signal_error(plist, param_name, ecode);
589     }
590     if ((code = param_anti_alias_bits(plist, "TextAlphaBits", &tab)) < 0)
591 	ecode = code;
592     if ((code = param_anti_alias_bits(plist, "GraphicsAlphaBits", &gab)) < 0)
593 	ecode = code;
594 
595     switch (code = param_read_bool(plist, (param_name = ".LockSafetyParams"), &locksafe)) {
596 	case 0:
597 	    if (dev->LockSafetyParams && !locksafe)
598 		code = gs_note_error(gs_error_invalidaccess);
599 	    else
600 		break;
601 	default:
602 	    ecode = code;
603 	    param_signal_error(plist, param_name, ecode);
604 	case 1:
605 	    break;
606     }
607     /* Ignore parameters that only have meaning for printers. */
608 #define IGNORE_INT_PARAM(pname)\
609   { int igni;\
610     switch ( code = param_read_int(plist, (param_name = pname), &igni) )\
611       { default:\
612 	  ecode = code;\
613 	  param_signal_error(plist, param_name, ecode);\
614 	case 0:\
615 	case 1:\
616 	  break;\
617       }\
618   }
619     IGNORE_INT_PARAM("%MediaSource")
620 	IGNORE_INT_PARAM("%MediaDestination")
621 	switch (code = param_read_float_array(plist, (param_name = "ImagingBBox"), &ibba)) {
622 	case 0:
623 	    if (ibba.size != 4 ||
624 		ibba.data[2] < ibba.data[0] || ibba.data[3] < ibba.data[1]
625 		)
626 		ecode = gs_note_error(gs_error_rangecheck);
627 	    else
628 		break;
629 	    goto ibbe;
630 	default:
631 	    if ((code = param_read_null(plist, param_name)) == 0) {
632 		ibbnull = true;
633 		ibba.data = 0;
634 		break;
635 	    }
636 	    ecode = code;	/* can't be 1 */
637 	  ibbe:param_signal_error(plist, param_name, ecode);
638 	case 1:
639 	    ibba.data = 0;
640 	    break;
641     }
642 
643     /* Now check nominally read-only parameters. */
644     if ((code = param_check_string(plist, "OutputDevice", dev->dname, true)) < 0)
645 	ecode = code;
646     if ((code = param_check_string(plist, "ProcessColorModel", pcmsa[colors], colors != 0)) < 0)
647 	ecode = code;
648     if ((code = param_check_int(plist, "MaxSeparations", 1, true)) < 0)
649 	ecode = code;
650     if ((code = param_check_bool(plist, "Separations", false, true)) < 0)
651 	ecode = code;
652     BEGIN_ARRAY_PARAM(param_read_name_array, "SeparationColorNames", scna, 0, scne) {
653 	break;
654     } END_ARRAY_PARAM(scna, scne);
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, colors > 1)) < 0)
666 	ecode = code;
667     if ((code = param_check_int(plist, "GreenValues", RGBValues, colors > 1)) < 0)
668 	ecode = code;
669     if ((code = param_check_int(plist, "BlueValues", RGBValues, colors > 1)) < 0)
670 	ecode = code;
671     if ((code = param_check_long(plist, "ColorValues", ColorValues, colors > 1)) < 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 defined)806 param_check_bool(gs_param_list * plist, gs_param_name pname, bool value,
807 		 bool 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 (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 defined)828 param_check_long(gs_param_list * plist, gs_param_name pname, long value,
829 		 bool 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 (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 defined)850 param_check_bytes(gs_param_list * plist, gs_param_name pname, const byte * str,
851 		  uint size, bool 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 (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