1 /******************************************************************************
2   File:     $Id: gdevpcl3.c,v 1.32 2001/08/14 15:22:35 Martin Rel $
3   Contents: Ghostscript device 'pcl3' for PCL-3+ printers
4   Author:   Martin Lottermoser, Greifswaldstrasse 28, 38124 Braunschweig,
5             Germany. E-mail: Martin.Lottermoser@t-online.de.
6 
7 *******************************************************************************
8 *									      *
9 *	Copyright (C) 2000, 2001 by Martin Lottermoser			      *
10 *	All rights reserved						      *
11 *									      *
12 *******************************************************************************
13 
14   Preprocessor symbols:
15 
16     GS_REVISION (integer)
17 	If defined, this must be the ghostscript version number, e.g., 601 for
18 	ghostscript 6.01.
19 
20     PCL3_MEDIA_FILE (const char *)
21 	Define this to set a media configuration file for the "unspec" device
22 	unless the user overrides it.
23 
24 ******************************************************************************/
25 
26 /* Configuration management identification */
27 #ifndef lint
28 static const char
29   cm_id[] = "@(#)$Id: gdevpcl3.c,v 1.32 2001/08/14 15:22:35 Martin Rel $";
30 #endif
31 
32 /*****************************************************************************/
33 
34 #ifndef _XOPEN_SOURCE
35 #define _XOPEN_SOURCE	500
36 #endif
37 
38 /* Special Aladdin header, must be included before <sys/types.h> on some
39    platforms (e.g., FreeBSD). */
40 #include "std.h"
41 
42 /* Standard headers */
43 #include <assert.h>
44 #include <ctype.h>
45 #include <errno.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 
50 /* Ghostscript headers */
51 #ifdef EPRN_TRACE
52 #include "gdebug.h"
53 #endif	/* EPRN_TRACE */
54 
55 /* Driver-specific headers */
56 #include "gdeveprn.h"
57 #include "pclcap.h"
58 #include "pclgen.h"
59 #include "pclsize.h"
60 
61 /*****************************************************************************/
62 
63 /* Does the argument point to an instance of the generic (pcl3) device? */
64 #define is_generic_device(dev)	(strcmp(dev->dname, "pcl3") == 0)
65 
66 /*****************************************************************************/
67 
68 /* Combined type with a range of bool plus null */
69 typedef enum {bn_null, bn_true, bn_false} bool_or_null;
70 
71 /* Type for duplex capabilities */
72 typedef enum {Duplex_none, Duplex_sameLeadingEdge, Duplex_oppositeLeadingEdge,
73   Duplex_both} DuplexCapabilities;
74 
75 /* Device structure */
76 typedef struct {
77   gx_eprn_device_common;	/* eprn part including base types */
78 
79   /* Printer selection and other data not directly mappable to PCL */
80   pcl_Printer printer;
81   bool_or_null use_card;
82   DuplexCapabilities duplex_capability;
83   bool tumble;	/* only relevant if 'Duplex' is 'true' */
84 
85   /* PCL generation */
86   bool
87     initialized,	/* Has init() been run on this device instance? */
88     configured,		/* Has the output file been configured? */
89     configure_every_page;  /* Repeat the configuration for every page? */
90   pcl_FileData file_data;
91 } pcl3_Device;
92 
93 /*****************************************************************************/
94 
95 /* Device procedures */
96 static dev_proc_open_device(pcl3_open_device);
97 static dev_proc_close_device(pcl3_close_device);
98 static dev_proc_get_params(pcl3_get_params);
99 static dev_proc_put_params(pcl3_put_params);
100 
101 /* Device procedure table */
102 static gx_device_procs pcl3_procs = {
103   eprn_procs_initdata(pcl3_open_device, pcl3_close_device, pcl3_get_params,
104     pcl3_put_params)
105 };
106 
107 /* prn procedure implementations */
108 #if !defined(GS_REVISION) || GS_REVISION >= 550
109 static prn_dev_proc_print_page(pcl3_print_page);
110 #else
111 static dev_proc_print_page(pcl3_print_page);
112 #endif
113 
114 /*****************************************************************************/
115 
116 /* Media flags known to this device in addition to the standard ones */
117 static const ms_Flag
118   flag_description[] = {
119     {PCL_CARD_FLAG, PCL_CARD_STRING},
120     {ms_none, NULL}
121   };
122 
123 /* List of possible optional media flags */
124 static const ms_MediaCode
125   card_is_optional[] = {PCL_CARD_FLAG, ms_none};
126 
127 /*****************************************************************************/
128 
129 /* Forward declaration */
130 static void pcl3_flag_mismatch_reporter(FILE *err,
131   const struct s_eprn_Device *eprn, bool no_match);
132 
133 /* Macro for creating device structure instances */
134 #define pcl3_device_instance(dname, printer)			\
135   pcl3_Device gs_##dname##_device = {				\
136     eprn_device_initdata(					\
137       pcl3_Device,	/* device type */			\
138       pcl3_procs,	/* static device procedure table */	\
139       #dname,		/* device name */			\
140       300.0, 300.0,	/* horizontal and vertical resolution */\
141       pcl3_print_page,	/* print page routine */		\
142       &pcl3_printers[printer].desc, /* printer capability description */ \
143       flag_description,	/* flag descriptions */			\
144       ms_none,		/* desired media flags */		\
145       card_is_optional,	/* list of optional flags */		\
146       &pcl3_flag_mismatch_reporter),	/* reporting function */\
147     printer,		/* printer */				\
148     bn_null,		/* use_card */				\
149     Duplex_none,	/* duplex_capability */			\
150     false,		/* tumble */				\
151     false		/* initialized */			\
152     /* The remaining fields will be set in init(). */		\
153   }
154 
155 /* Generic and flexible device structure instance */
156 pcl3_device_instance(pcl3, pcl3_generic_new);
157 
158 /* Printer-specific and fixed device structure instances */
159 /* At present there is no entry for the HP DeskJet because its natural name
160    collides with the hpdj driver. */
161 pcl3_device_instance(hpdjplus,	HPDeskJetPlus);
162 pcl3_device_instance(hpdjportable, HPDJPortable);
163 pcl3_device_instance(hpdj310,	HPDJ310);
164 pcl3_device_instance(hpdj320,	HPDJ320);
165 pcl3_device_instance(hpdj340,	HPDJ340);
166 pcl3_device_instance(hpdj400,	HPDJ400);
167 pcl3_device_instance(hpdj500,	HPDJ500);
168 pcl3_device_instance(hpdj500c,	HPDJ500C);
169 pcl3_device_instance(hpdj510,	HPDJ510);
170 pcl3_device_instance(hpdj520,	HPDJ520);
171 pcl3_device_instance(hpdj540,	HPDJ540);
172 pcl3_device_instance(hpdj550c,	HPDJ550C);
173 pcl3_device_instance(hpdj560c,	HPDJ560C);
174 pcl3_device_instance(hpdj600,	HPDJ600);
175 pcl3_device_instance(hpdj660c,	HPDJ660C);
176 pcl3_device_instance(hpdj670c,	HPDJ670C);
177 pcl3_device_instance(hpdj680c,	HPDJ680C);
178 pcl3_device_instance(hpdj690c,	HPDJ690C);
179 pcl3_device_instance(hpdj850c,	HPDJ850C);
180 pcl3_device_instance(hpdj855c,	HPDJ855C);
181 pcl3_device_instance(hpdj870c,	HPDJ870C);
182 pcl3_device_instance(hpdj890c,	HPDJ890C);
183 pcl3_device_instance(hpdj1120c,	HPDJ1120C);
184 
185 /*****************************************************************************/
186 
187 #define ERRPREF		"? pcl3: "
188 #define WARNPREF	"?-W pcl3: "
189 
190 #define array_size(a)	(sizeof(a)/sizeof(a[0]))
191 
192 /*****************************************************************************/
193 
194 static const eprn_StringAndInt
195   /* Names for duplex capabilities */
196   duplex_capabilities_list[] = {
197     { "none",		Duplex_none },
198     { "sameLeadingEdge", Duplex_sameLeadingEdge },
199     { "oppositeLeadingEdge", Duplex_oppositeLeadingEdge },
200     { "both",		Duplex_both },
201     { NULL,		0 }
202   },
203   /* Names for PCL Media Type values */
204   media_type_list[] = {
205     /* Canonical names */
206     { "plain paper",	0 },
207     { "bond paper",	1 },
208     { "HP Premium paper", 2 },
209     { "glossy paper",	3 },
210     { "transparency film", 4 },
211     { "quick dry glossy", 5 },
212     { "quick dry transparency", 6 },
213     /* Shortened names */
214     { "plain",		0 },
215     { "bond",		1 },
216     { "Premium",	2 },
217     { "glossy",		3 },
218     { "transparency",	4 },
219     { NULL,		0 }
220   },
221   /* Print Quality */
222   print_quality_list[] = {
223     { "draft",	       -1 },
224     { "normal",		0 },
225     { "presentation",	1 },
226     /* Start of synonyms */
227     { "econo",		-1 },
228     { "best",		1 },
229     { NULL,		0 }
230   },
231   /* Subdevice names. They must be ordered by 'value' except for the last
232      (NULL) entry. At present, there are 26 non-NULL entries here. */
233   subdevice_list[] = {
234     { "hpdj",		HPDeskJet },
235     { "hpdjplus",	HPDeskJetPlus },
236     { "hpdjportable",	HPDJPortable },
237     { "hpdj310",	HPDJ310 },
238     { "hpdj320",	HPDJ320 },
239     { "hpdj340",	HPDJ340 },
240     { "hpdj400",	HPDJ400 },
241     { "hpdj500",	HPDJ500 },
242     { "hpdj500c",	HPDJ500C },
243     { "hpdj510",	HPDJ510 },
244     { "hpdj520",	HPDJ520 },
245     { "hpdj540",	HPDJ540 },
246     { "hpdj550c",	HPDJ550C },
247     { "hpdj560c",	HPDJ560C },
248     { "unspecold",	pcl3_generic_old },
249     { "hpdj600",	HPDJ600 },
250     { "hpdj660c",	HPDJ660C },
251     { "hpdj670c",	HPDJ670C },
252     { "hpdj680c",	HPDJ680C },
253     { "hpdj690c",	HPDJ690C },
254     { "hpdj850c",	HPDJ850C },
255     { "hpdj855c",	HPDJ855C },
256     { "hpdj870c",	HPDJ870C },
257     { "hpdj890c",	HPDJ890C },
258     { "hpdj1120c",	HPDJ1120C },
259     { "unspec",		pcl3_generic_new },
260     { NULL,		0 }
261   };
262 
263 /******************************************************************************
264 
265   Function: cmp_by_value
266 
267   This function compares two 'eprn_StringAndInt' instances by their 'value'
268   fields.
269 
270 ******************************************************************************/
271 
cmp_by_value(const void * a,const void * b)272 static int cmp_by_value(const void *a, const void *b)
273 {
274   return ((const eprn_StringAndInt *)a)->value -
275     ((const eprn_StringAndInt *)b)->value;
276 }
277 
278 /******************************************************************************
279 
280   Function: get_string_for_int
281 
282   This function returns a string representation of 'in_value' in '*out_value',
283   based on 'table'. 'table' must be an array terminated with an entry having
284   NULL as the 'name' value and must be permanently allocated and constant.
285   If 'in_value' cannot be found in 'table', the function returns a decimal
286   representation of 'in_value'.
287 
288   The string buffer in '*out_value' will be a permanently allocated area which
289   must not be modified.
290 
291 ******************************************************************************/
292 
get_string_for_int(int in_value,const eprn_StringAndInt * table,gs_param_string * out_value)293 static void get_string_for_int(int in_value, const eprn_StringAndInt *table,
294   gs_param_string *out_value)
295 {
296   while (table->name != NULL && table->value != in_value) table++;
297   if (table->name != NULL) {
298     out_value->data = (const byte *)table->name;
299     out_value->size = strlen(table->name);
300     out_value->persistent = true;
301   }
302   else {
303     static char buffer[22];	/* Must be sufficient for an 'int' */
304 
305     sprintf(buffer, "%d", in_value);
306     assert(strlen(buffer) < sizeof(buffer));
307     out_value->data = (const byte *)buffer;
308     out_value->size = strlen(buffer);
309     out_value->persistent = false;
310   }
311 
312   return;
313 }
314 
315 /******************************************************************************
316 
317   Function: get_int_for_string
318 
319   This function parses 'in_value' based on 'table' and returns the result in
320   '*out_value'. 'table' must be an array, terminated with an entry having NULL
321   as the value for 'name'.
322 
323   'in_value' must either be a decimal representation of an integer or must be
324   a string present in 'table'. In these cases, the function returns 0,
325   otherwise a non-zero ghostscript error value.
326 
327   On returning 'gs_error_VMerror', the function will have issued an error
328   message.
329 
330 ******************************************************************************/
331 
get_int_for_string(const gs_param_string * in_value,const eprn_StringAndInt * table,int * out_value)332 static int get_int_for_string(const gs_param_string *in_value,
333   const eprn_StringAndInt *table, int *out_value)
334 {
335   char *s;
336   int read;	/* counter */
337 
338   /* First we construct a properly NUL-terminated string */
339   s = (char *) malloc(in_value->size + 1);
340   if (s == NULL) {
341     eprintf1(ERRPREF
342       "Memory allocation failure in get_int_for_string(): %s.\n",
343       strerror(errno));
344     return_error(gs_error_VMerror);
345   }
346   strncpy(s, (const char *)in_value->data, in_value->size);
347   s[in_value->size] = '\0';
348 
349   /* To foil bugs in sscanf() on Windows (see gdeveprn.c in eprn) I'm removing
350      trailing white space here instead of skipping it with a format. */
351   {
352     char *t = strchr(s, '\0');
353 
354     while (s < t && isspace(*(t-1))) t--;
355     *t = '\0';
356   }
357 
358   /* Check for a numerical value */
359   if (sscanf(s, "%d%n", out_value, &read) != 1 || s[read] != '\0') {
360     /* What the user specified is not a valid numerical value */
361     while (table->name != NULL && strcmp(table->name, s) != 0) table++;
362     if (table->name == NULL) {
363       free(s); s = NULL;
364       return_error(gs_error_rangecheck);
365     }
366     *out_value = table->value;
367   }
368 
369   free(s); s = NULL;
370 
371   return 0;
372 }
373 
374 /******************************************************************************
375 
376   Function: init
377 
378   This function does that part of initialization which cannot be performed at
379   compile time or which must be repeated whenever the subdevice is changed.
380   It must be called if 'initialized' is false and after the subdevice is
381   changed.
382 
383   When this function is called, 'dev->printer' must have been set correctly.
384 
385   This function must not and does not depend on the state of initialization of
386   its base devices.
387 
388 ******************************************************************************/
389 
init(pcl3_Device * dev)390 static void init(pcl3_Device *dev)
391 {
392 #ifndef NDEBUG
393   /* Check that 'subdevice_list' is sorted by 'value' */
394   {
395     int j;
396     for (j = 1; j < array_size(subdevice_list) - 1; j++)
397       assert(cmp_by_value(subdevice_list + j - 1, subdevice_list + j) <= 0);
398   }
399 #endif	/* !NDEBUG */
400 
401   /* Base class fields */
402   if (is_generic_device(dev)) dev->Duplex_set = 0;
403    /* "Duplex" is null. See remarks on the "Duplex" page device parameter in
404       pcl3_put_params(). */
405 
406   /* pcl3 fields */
407   dev->use_card = bn_null;
408   dev->duplex_capability = Duplex_none;
409   dev->tumble = false;
410   dev->configured = false;
411   dev->configure_every_page = false;
412 
413   /* Initialize 'file_data' */
414   pcl3_fill_defaults(dev->printer, &dev->file_data);
415 
416   dev->initialized = true;
417 
418   return;
419 }
420 
421 /******************************************************************************
422 
423   Function: pcl3_flag_mismatch_reporter
424 
425   Flag mismatch reporting function for the pcl3 device.
426 
427   The 'desired_flags' field can only contain MS_BIG_FLAG and PCL_CARD_FLAG.
428 
429 ******************************************************************************/
430 
pcl3_flag_mismatch_reporter(FILE * err,const struct s_eprn_Device * eprn,bool no_match)431 static void pcl3_flag_mismatch_reporter(FILE *err,
432   const struct s_eprn_Device *eprn, bool no_match)
433 {
434   const char *epref = eprn->CUPS_messages? CUPS_ERRPREF: "";
435 
436   if (eprn->desired_flags == 0) {
437     eprintf2(
438       "%s" ERRPREF "The %s does not support the requested media properties.\n",
439       epref, eprn->cap->name);
440   }
441   else if (eprn->desired_flags == MS_BIG_FLAG) {
442     eprintf2("%s" ERRPREF "The %s does not support banner printing",
443       epref, eprn->cap->name);
444     if (!no_match) eprintf(" for this size");
445     eprintf(".\n");
446   }
447   else if (eprn->desired_flags == PCL_CARD_FLAG) {
448     eprintf2("%s" ERRPREF
449       "The %s does not support a `Card' variant for ",
450       epref, eprn->cap->name);
451     if (no_match) eprintf("any"); else eprintf("this");
452     eprintf(" size.\n");
453   }
454   else {
455     eprintf1(
456       "%s" ERRPREF "Banner printing on postcards?? You must be joking!\n",
457       epref);
458   }
459 
460   return;
461 }
462 
463 /******************************************************************************
464 
465   Function: find_subdevice_name
466 
467   This function returns a pointer to a static storage location containing
468   a NUL-terminated string with the name of the subdevice for 'subdev'.
469 
470   It must not be called for invalid 'subdev' values.
471 
472 ******************************************************************************/
473 
find_subdevice_name(int subdev)474 static const char *find_subdevice_name(int subdev)
475 {
476   eprn_StringAndInt
477     key = {NULL, 0};
478   const eprn_StringAndInt
479     *found;
480 
481   key.value = subdev;
482 
483   found = (const eprn_StringAndInt *)bsearch(&key, subdevice_list,
484     array_size(subdevice_list) - 1, sizeof(eprn_StringAndInt), cmp_by_value);
485   assert(found != NULL);
486 
487   return found->name;
488 }
489 
490 /******************************************************************************
491 
492   Function: pcl3_get_params
493 
494   This function returns to the caller information about the values of
495   parameters defined for the device. This includes parameters defined in base
496   classes.
497 
498   The function returns zero on success and a negative value on error.
499 
500 ******************************************************************************/
501 
pcl3_get_params(gx_device * device,gs_param_list * plist)502 static int pcl3_get_params(gx_device *device, gs_param_list *plist)
503 {
504   gs_param_string string_value;
505   pcl3_Device *dev = (pcl3_Device *)device;
506   const pcl_FileData *data = &dev->file_data;
507   int
508     temp,  /* Used as an intermediate for various reasons */
509     rc;
510 
511   /* Constructor */
512   if (!dev->initialized) init(dev);
513 
514   /* Base class parameters */
515   rc = eprn_get_params(device, plist);
516   if (rc < 0) return rc;
517 
518   /* Compression method */
519   temp = data->compression;
520   if ((rc = param_write_int(plist, "CompressionMethod", &temp)) < 0) return rc;
521 
522   /* Configure every page */
523   if ((rc = param_write_bool(plist, "ConfigureEveryPage",
524     &dev->configure_every_page)) < 0) return rc;
525 
526   /* Dry time */
527   if (data->dry_time < 0) {
528     if ((rc = param_write_null(plist, "DryTime")) < 0) return rc;
529   }
530   else if ((rc = param_write_int(plist, "DryTime", &data->dry_time)) < 0)
531     return rc;
532 
533   /* Duplex capability */
534   if (is_generic_device(dev)) {
535     eprn_get_string(dev->duplex_capability, duplex_capabilities_list,
536       &string_value);
537     if ((rc = param_write_string(plist, "DuplexCapability", &string_value)) < 0)
538       return rc;
539   }
540 
541   /* Manual feed */
542   {
543     bool temp = dev->file_data.manual_feed;
544     if ((rc = param_write_bool(plist, "ManualFeed", &temp)) < 0) return rc;
545   }
546 
547   /* PCL media type */
548   get_string_for_int(data->media_type, media_type_list, &string_value);
549   if ((rc = param_write_string(plist, "Medium", &string_value)) < 0)
550     return rc;
551 
552   /* Media destination */
553   if ((rc = param_write_int(plist, "%MediaDestination",
554     &data->media_destination)) < 0) return rc;
555 
556   /* Media source */
557   if ((rc = param_write_int(plist, "%MediaSource", &data->media_source)) < 0)
558     return rc;
559 
560   /* Use of Configure Raster Data */
561   if (is_generic_device(dev) || pcl_has_CRD(data->level)) {
562     bool temp = (data->level == pcl_level_3plus_CRD_only);
563     if ((rc = param_write_bool(plist, "OnlyCRD", &temp)) < 0) return rc;
564   }
565 
566   /* PCL initilization strings */
567   if (data->init1.length == 0) {
568     if ((rc = param_write_null(plist, "PCLInit1")) < 0) return rc;
569   }
570   else {
571     string_value.data = (const byte *)data->init1.str;
572     string_value.size = data->init1.length;
573     string_value.persistent = false;
574     if ((rc = param_write_string(plist, "PCLInit1", &string_value)) < 0)
575       return rc;
576   }
577   if (data->init2.length == 0) {
578     if ((rc = param_write_null(plist, "PCLInit2")) < 0) return rc;
579   }
580   else {
581     string_value.data = (const byte *)data->init2.str;
582     string_value.size = data->init2.length;
583     string_value.persistent = false;
584     if ((rc = param_write_string(plist, "PCLInit2", &string_value)) < 0)
585       return rc;
586   }
587 
588   /* PJL job name */
589   if (data->PJL_job == NULL) {
590     if ((rc = param_write_null(plist, "PJLJob")) < 0) return rc;
591   }
592   else {
593     string_value.data = (const byte *)data->PJL_job;
594     string_value.size = strlen(data->PJL_job);
595     string_value.persistent = false;
596     if ((rc = param_write_string(plist, "PJLJob", &string_value)) < 0)
597       return rc;
598   }
599 
600   /* PJL language */
601   if (data->PJL_language == NULL) {
602     if ((rc = param_write_null(plist, "PJLLanguage")) < 0) return rc;
603   }
604   else {
605     string_value.data = (const byte *)data->PJL_language;
606     string_value.size = strlen(data->PJL_language);
607     string_value.persistent = false;
608     if ((rc = param_write_string(plist, "PJLLanguage", &string_value)) < 0)
609       return rc;
610   }
611 
612   /* Print quality */
613   get_string_for_int(data->print_quality, print_quality_list, &string_value);
614   if ((rc = param_write_string(plist, "PrintQuality", &string_value)) < 0)
615     return rc;
616 
617   /* Black bit planes first (standard PCL) or last */
618   {
619     bool temp = (data->order_CMYK == TRUE);
620     if ((rc = param_write_bool(plist, "SendBlackLast", &temp)) < 0) return rc;
621   }
622 
623   /* NUL header */
624   if ((rc = param_write_int(plist, "SendNULs", &data->NULs_to_send)) < 0)
625     return rc;
626 
627   /* Subdevice name, but only for the generic device */
628   if (is_generic_device(dev)) {
629     const char *name = find_subdevice_name(dev->printer);
630     string_value.data = (const byte *)name;
631     string_value.size = strlen(name);
632     string_value.persistent = true;
633     if ((rc = param_write_string(plist, "Subdevice", &string_value)) < 0)
634       return rc;
635   }
636 
637   /* Tumble */
638   if (is_generic_device(dev))
639     if ((rc = param_write_bool(plist, "Tumble", &dev->tumble)) < 0) return rc;
640 
641   /* UseCard */
642   if (dev->use_card == bn_null) {
643     if ((rc = param_write_null(plist, "UseCard")) < 0) return rc;
644   }
645   else {
646     bool temp = (dev->use_card == bn_true);
647     if ((rc = param_write_bool(plist, "UseCard", &temp)) < 0) return rc;
648   }
649 
650   /* The old quality commands if they have meaning for this device */
651   if (pcl_use_oldquality(data->level)) {
652     /* Depletion */
653     if (data->depletion == 0) {
654       if ((rc = param_write_null(plist, "Depletion")) < 0) return rc;
655     }
656     else if ((rc = param_write_int(plist, "Depletion", &data->depletion)) < 0)
657       return rc;
658 
659     /* Raster Graphics Quality */
660     if ((rc = param_write_int(plist, "RasterGraphicsQuality",
661       &data->raster_graphics_quality)) < 0) return rc;
662 
663     /* Shingling */
664     if ((rc = param_write_int(plist, "Shingling", &data->shingling)) < 0)
665       return rc;
666   }
667   else if (is_generic_device(dev)) {
668     /* It is logically wrong for these parameters to be visible if we are
669        dealing with a group-3 device, but I haven't yet found a way to get
670        around ghostscript's undefined-parameter-update problem. */
671     if ((rc = param_write_null(plist, "Depletion")) < 0) return rc;
672     if ((rc = param_write_null(plist, "RasterGraphicsQuality")) < 0) return rc;
673     if ((rc = param_write_null(plist, "Shingling")) < 0) return rc;
674   }
675 
676 #ifdef EPRN_TRACE
677   if (gs_debug_c(EPRN_TRACE_CHAR)) {
678     dlprintf("! pcl3_get_params() returns the following parameters:\n");
679     eprn_dump_parameter_list(plist);
680   }
681 #endif
682 
683   return 0;
684 }
685 
686 /******************************************************************************
687 
688   Function: fetch_octets
689 
690   This function checks whether 'plist' contains a string entry for the parameter
691   'pname' and returns the value via '*s' if it does.
692 
693   Neither 'plist' nor 'pname' may be NULL. On entry, '*s' must be a valid octet
694   string; if it is non-zero, 's->str' must point to a gs_malloc()-allocated
695   storage area of length 's->length'.
696 
697   If the parameter exists in 'plist', its type must be null or string. If it is
698   null, '*s' will become zero. If the parameter type is string, the value will
699   be copied to '*s'.
700 
701   The function returns a negative ghostscript error code on error and zero
702   otherwise. In the former case an error message will have been issued,
703   using 'epref' as a prefix for the message.
704 
705 ******************************************************************************/
706 
fetch_octets(const char * epref,gs_param_list * plist,const char * pname,pcl_OctetString * s)707 static int fetch_octets(const char *epref,
708   gs_param_list *plist, const char *pname, pcl_OctetString *s)
709 {
710   gs_param_string string_value;
711   int rc;
712 
713   if ((rc = param_read_null(plist, pname)) == 0) {
714     if (s->length != 0)
715       gs_free(gs_lib_ctx_get_non_gc_memory_t(), s->str, s->length, sizeof(pcl_Octet), "fetch_octets");
716     s->str = NULL;
717     s->length = 0;
718   }
719   else if (rc < 0 &&
720       (rc = param_read_string(plist, pname, &string_value)) == 0) {
721     /* Free old storage */
722     if (s->length != 0)
723       gs_free(gs_lib_ctx_get_non_gc_memory_t(), s->str, s->length, sizeof(pcl_Octet), "fetch_octets");
724 
725     /* Allocate new */
726     s->str = (pcl_Octet *)gs_malloc(gs_lib_ctx_get_non_gc_memory_t(), string_value.size, sizeof(pcl_Octet),
727       "fetch_octets");
728 
729     if (s->str == NULL) {
730       s->length = 0;
731       eprintf1("%s" ERRPREF
732 	"Memory allocation failure from gs_malloc().\n", epref);
733       rc = gs_error_VMerror;
734       param_signal_error(plist, pname, rc);
735     }
736     else {
737       memcpy(s->str, string_value.data, string_value.size);
738       s->length = string_value.size;
739     }
740   }
741   else if (rc > 0) rc = 0;
742 
743   return rc;
744 }
745 
746 /******************************************************************************
747 
748   Function: fetch_cstring
749 
750   This function checks whether 'plist' contains a string entry for the parameter
751   'pname' and returns the value via '*s' if it does.
752 
753   Neither 'plist' nor 'pname' may be NULL. On entry, '*s' must be NULL or point
754   to a NUL-terminated string in a gs_malloc()-allocated storage area.
755 
756   If the parameter exists in 'plist', its type must be null or string. If it is
757   null, '*s' will be gs_free()d and set to NULL. If it is a string, '*s' will
758   be reallocated to contain the NUL-terminated value of the string. Should the
759   string already contain a NUL value, only the part up to the NUL will be
760   copied.
761 
762   The function returns a negative ghostscript error code on error and zero
763   otherwise. In the former case an error message will have been issued.
764 
765 ******************************************************************************/
766 
fetch_cstring(const char * epref,gs_param_list * plist,const char * pname,char ** s)767 static int fetch_cstring(const char *epref,
768   gs_param_list *plist, const char *pname, char **s)
769 {
770   gs_param_string string_value;
771   int rc;
772 
773   if ((rc = param_read_null(plist, pname)) == 0) {
774     if (*s != NULL) gs_free(gs_lib_ctx_get_non_gc_memory_t(), *s, strlen(*s) + 1, sizeof(char), "fetch_cstring");
775     *s = NULL;
776   }
777   else if (rc < 0 &&
778       (rc = param_read_string(plist, pname, &string_value)) == 0) {
779     /* Free old storage */
780     if (*s != NULL) gs_free(gs_lib_ctx_get_non_gc_memory_t(), *s, strlen(*s) + 1, sizeof(char), "fetch_cstring");
781 
782     /* Allocate new */
783     *s = (char *)gs_malloc(gs_lib_ctx_get_non_gc_memory_t(), string_value.size + 1, sizeof(char),
784       "fetch_cstring");
785 
786     if (*s == NULL) {
787       eprintf1("%s" ERRPREF
788 	"Memory allocation failure from gs_malloc().\n", epref);
789       rc = gs_error_VMerror;
790       param_signal_error(plist, pname, rc);
791     }
792     else {
793       strncpy(*s, (const char*)string_value.data, string_value.size);
794       (*s)[string_value.size] = '\0';
795     }
796   }
797   else if (rc > 0) rc = 0;
798 
799   return rc;
800 }
801 
802 /******************************************************************************
803 
804   Function: set_palette
805 
806   This function sets 'dev->file_data.palette' and some other fields in
807   agreement with 'dev->eprn.colour_model'.
808 
809 ******************************************************************************/
810 
set_palette(pcl3_Device * dev)811 static void set_palette(pcl3_Device *dev)
812 {
813   pcl_FileData *data = &dev->file_data;
814 
815   switch(dev->eprn.colour_model) {
816   case eprn_DeviceGray:
817     {
818       const eprn_ColourInfo *ci = dev->eprn.cap->colour_info;
819 
820       /* Can this printer switch palettes? */
821       while (ci->info[0] != NULL && ci->colour_model == eprn_DeviceGray) ci++;
822       if (ci->info[0] != NULL) data->palette = pcl_black;
823       else data->palette = pcl_no_palette;
824     }
825     data->number_of_colorants = 1;
826     data->depletion = 0;	/* Depletion is only meaningful for colour. */
827     break;
828   case eprn_DeviceCMY:
829     data->palette = pcl_CMY;
830     data->number_of_colorants = 3;
831     break;
832   case eprn_DeviceRGB:
833     data->palette = pcl_RGB;
834     data->number_of_colorants = 3;
835     break;
836   case eprn_DeviceCMY_plus_K:
837     /*FALLTHROUGH*/
838   case eprn_DeviceCMYK:
839     data->palette = pcl_CMYK;
840     data->number_of_colorants = 4;
841     break;
842   default:
843     assert(0);
844   }
845 
846   return;
847 }
848 
849 /******************************************************************************
850 
851   Function: pcl3_put_params
852 
853   This function reads a parameter list, extracts the parameters known to the
854   device, and configures the device appropriately. This includes parameters
855   defined by base classes.
856 
857   If an error occurs in the processing of parameters, the function will
858   return a negative value, otherwise zero.
859 
860   This function does *not* exhibit transactional behaviour as requested in
861   gsparam.h, i.e. on error the parameter values in the device structure
862   might have changed. However, all values will be individually valid.
863 
864   Some of the parameters determine derived data in base classes or are relevant
865   for device initialization. Setting any of these parameters closes the
866   device if it is open.
867 
868 ******************************************************************************/
869 
pcl3_put_params(gx_device * device,gs_param_list * plist)870 static int pcl3_put_params(gx_device *device, gs_param_list *plist)
871 {
872   bool new_quality = false;	/* has someone requested the new variables? */
873   gs_param_name pname;
874   gs_param_string string_value;
875   pcl3_Device *dev = (pcl3_Device *)device;
876   const char
877     *epref = dev->eprn.CUPS_messages? CUPS_ERRPREF: "",
878     *wpref = dev->eprn.CUPS_messages? CUPS_WARNPREF: "";
879   eprn_ColourModel previous_colour_model = dev->eprn.colour_model;
880   pcl_FileData *data = &dev->file_data;
881   int
882     last_error = 0,
883     temp,
884     rc;
885   struct {
886     int depletion, quality, shingling;
887   } requested = {-1, -1, -1};
888     /* old quality parameters. -1 means "not specified". */
889 
890   /* Check for subdevice selection */
891   if (is_generic_device(dev)) {
892     if ((rc = param_read_string(plist, (pname = "Subdevice"), &string_value))
893         == 0) {
894       /* This property must be a known string. */
895       int j = 0;
896       while (subdevice_list[j].name != NULL &&
897 	  (string_value.size != strlen(subdevice_list[j].name) ||
898 	    strncmp((const char *)string_value.data, subdevice_list[j].name,
899 	      string_value.size) != 0))
900 	j++;
901 	/* param_read_string() does not return NUL-terminated strings. */
902       if (subdevice_list[j].name != NULL) {
903 	if (dev->is_open) gs_closedevice(device);
904 	dev->printer = subdevice_list[j].value;
905 	dev->initialized = false;
906 	eprn_init_device((eprn_Device *)dev, &pcl3_printers[dev->printer].desc);
907       }
908       else {
909 	eprintf1("%s" ERRPREF "Unknown subdevice name: `", epref);
910 	errwrite(string_value.data, sizeof(char)*string_value.size);
911 	eprintf("'.\n");
912 	last_error = gs_error_rangecheck;
913 	param_signal_error(plist, pname, last_error);
914       }
915     }
916     else if (rc < 0) last_error = rc;
917   }
918 
919   /* Constructor */
920   if (!dev->initialized) init(dev);
921 
922   /* Compression method */
923   if ((rc = param_read_int(plist, (pname = "CompressionMethod"), &temp))
924       == 0) {
925     if (temp != pcl_cm_none && temp != pcl_cm_rl && temp != pcl_cm_tiff &&
926 	temp != pcl_cm_delta && temp != pcl_cm_crdr) {
927       eprintf2("%s" ERRPREF "Unsupported compression method: %d.\n",
928 	epref, temp);
929       last_error = gs_error_rangecheck;
930       param_signal_error(plist, pname, last_error);
931     }
932     else {
933       if (temp == pcl_cm_crdr && (dev->printer == HPDeskJet ||
934 	  dev->printer == HPDeskJetPlus || dev->printer == HPDJ500)) {
935 	/* This I know to be the case for the DJ 500. The others are guessed. */
936 	eprintf2(
937 	  "%s" ERRPREF "The %s does not support compression method 9.\n",
938 	  epref, dev->eprn.cap->name);
939 	last_error = gs_error_rangecheck;
940 	param_signal_error(plist, pname, last_error);
941       }
942       else data->compression= temp;
943     }
944   }
945   else if (rc < 0) last_error = rc;
946 
947   /* Configure every page */
948   if ((rc = param_read_bool(plist, "ConfigureEveryPage",
949     &dev->configure_every_page)) < 0) last_error = rc;
950 
951   /* Depletion */
952   if ((rc = param_read_null(plist, (pname = "Depletion"))) == 0)
953     requested.depletion = 0;
954   else if (rc < 0 && (rc = param_read_int(plist, pname, &temp)) == 0) {
955     if (1 <= temp && temp <= 5 && (dev->printer != HPDJ500C || temp <= 3))
956       requested.depletion = temp;
957     else {
958       eprintf2("%s" ERRPREF "Invalid value for depletion: %d.\n",
959 	epref, temp);
960       last_error = gs_error_rangecheck;
961       param_signal_error(plist, pname, last_error);
962     }
963   }
964   else if (rc < 0) last_error = rc;
965 
966   /* Dry time */
967   if ((rc = param_read_null(plist, (pname = "DryTime"))) == 0)
968     data->dry_time = -1;
969   else if (rc < 0 &&
970       (rc = param_read_int(plist, pname, &temp)) == 0) {
971     if (0 <= temp && temp <= 1200) {
972       if (dev->printer == HPDJ500 || dev->printer == HPDJ500C) {
973 	 /* According to HP (DJ6/8 p. 18), only some of the series 600 and 800
974 	    DeskJets respond to this command. I also suspect that the same is
975 	    true for pre-DeskJet-500 printers. This should not matter, though,
976 	    because the PCL interpreter should merely ignore the command.
977 	    Hence I'm giving an error message only in those cases where HP
978 	    explicitly states that the printer does not support the command.
979 	  */
980 	eprintf2(
981 	  "%s" ERRPREF "The %s does not support setting a dry time.\n",
982 	  epref, dev->eprn.cap->name);
983 	last_error = gs_error_rangecheck;
984 	param_signal_error(plist, pname, last_error);
985       }
986       else data->dry_time = temp;
987     }
988     else {
989       eprintf2("%s" ERRPREF "Invalid value for the dry time: %d.\n",
990 	epref, temp);
991       last_error = gs_error_rangecheck;
992       param_signal_error(plist, pname, last_error);
993     }
994   }
995   else if (rc < 0) last_error = rc;
996 
997   /* Duplex capability */
998   if (is_generic_device(dev)) {
999     if ((rc = param_read_string(plist, (pname = "DuplexCapability"),
1000 	&string_value)) == 0) {
1001       rc = eprn_get_int(&string_value, duplex_capabilities_list, &temp);
1002       if (rc == 0) {
1003 	if (dev->printer == pcl3_generic_new ||
1004 	    dev->printer == pcl3_generic_old || temp == Duplex_none) {
1005 	  dev->duplex_capability = temp;
1006 	  if (dev->duplex_capability == Duplex_none)
1007 	    dev->Duplex_set = 0;	/* force to "null" */
1008 	}
1009 	else {
1010 	  eprintf2("%s" ERRPREF
1011 	    "You can use a non-trivial value for DuplexCapability\n"
1012 	    "%s  only for unspec and unspecold.\n", epref, epref);
1013 	  last_error = gs_error_rangecheck;
1014 	  param_signal_error(plist, pname, last_error);
1015 	}
1016       }
1017       else {
1018 	eprintf1("%s" ERRPREF "Invalid duplex capability: `", epref);
1019 	errwrite(string_value.data, sizeof(char)*string_value.size);
1020 	eprintf("'.\n");
1021 	last_error = gs_error_rangecheck;
1022 	param_signal_error(plist, pname, last_error);
1023       }
1024     }
1025     else if (rc < 0) last_error = rc;
1026   }
1027 
1028   /* Check on "Duplex". This parameter is really read in gdev_prn_put_params(),
1029      but we check here to prevent it being set unless the printer really
1030      supports duplex printing. I would prefer to use the 'Duplex_set' variable
1031      for controlling the appearance of this page device parameter, but if I do,
1032      I can set the parameter only from PostScript and not from the command line.
1033   */
1034   {
1035     bool temp;
1036     if ((rc = param_read_bool(plist, (pname = "Duplex"), &temp)) == 0 &&
1037 	temp && dev->duplex_capability == Duplex_none) {
1038       if (dev->printer == pcl3_generic_new || dev->printer == pcl3_generic_old)
1039 	eprintf3("%s" ERRPREF
1040           "The '%s' device does not support duplex printing unless\n"
1041 	  "%s  'DuplexCapability' is not 'none'.\n",
1042 	  epref, find_subdevice_name(dev->printer), epref);
1043       else
1044 	eprintf2("%s" ERRPREF
1045 	  "The %s does not support duplex printing.\n",
1046 	  epref, dev->eprn.cap->name);
1047       last_error = gs_error_rangecheck;
1048       param_signal_error(plist, pname, last_error);
1049     }
1050     /* NO check of rc because "null" is legal. */
1051   }
1052 
1053   /* Manual feed */
1054   {
1055     bool temp;
1056     if ((rc = param_read_bool(plist, (pname = "ManualFeed"), &temp)) == 0)
1057       dev->file_data.manual_feed = temp;
1058     else if (rc < 0) last_error = rc;
1059   }
1060 
1061   /* PCL media type */
1062   if ((rc = param_read_string(plist, (pname = "Medium"), &string_value)) == 0) {
1063     /*  We accept numerical and string values. Numerical values at present
1064 	officially defined are 0-6, but not all printers know all these values.
1065 	We give the user the benefit of the doubt, though, because the
1066 	value is simply passed through to the printer, except for the older
1067 	DeskJets where we map illegal values to "plain paper".
1068 	If the user specifies a string, however, it must be a known one.
1069     */
1070     rc = get_int_for_string(&string_value, media_type_list, &temp);
1071     if (rc != 0) {
1072       if (rc != gs_error_VMerror) {
1073 	eprintf1("%s" ERRPREF "Unknown medium: `", epref);
1074 	errwrite(string_value.data, sizeof(char)*string_value.size);
1075 	eprintf("'.\n");
1076       }
1077       last_error = rc;
1078       param_signal_error(plist, pname, last_error);
1079     }
1080     else {
1081       new_quality = true;
1082       if (temp < 0 || 6 < temp)
1083 	eprintf2("%s" WARNPREF "Unknown media type code: %d.\n",
1084 	  wpref, temp);
1085       pcl3_set_mediatype(data, temp);
1086     }
1087   }
1088   else if (rc < 0) last_error = rc;
1089 
1090   /* Media destination */
1091   if ((rc = param_read_int(plist, (pname = "%MediaDestination"),
1092     &data->media_destination)) < 0) last_error = rc;
1093 
1094   /* Media source */
1095   if ((rc = param_read_int(plist, (pname = "%MediaSource"),
1096     &data->media_source)) < 0) last_error = rc;
1097   else if (rc == 0 && dev->is_open) gs_closedevice(device);
1098     /* In pcl3, %MediaSource is relevant for banner printing and hence page
1099        layout which is determined in the open routine. */
1100 
1101   /* Use of Configure Raster Data */
1102   if (is_generic_device(dev) || pcl_has_CRD(data->level)) {
1103     bool temp;
1104 
1105     if ((rc = param_read_bool(plist, (pname = "OnlyCRD"), &temp)) == 0) {
1106       if (pcl_has_CRD(data->level))
1107 	data->level = (temp? pcl_level_3plus_CRD_only: pcl_level_3plus_S68);
1108       else if (temp == true) {
1109 	eprintf1("%s" ERRPREF
1110 	  "OnlyCRD may be set only for group-3 devices.\n", epref);
1111 	last_error = gs_error_rangecheck;
1112 	param_signal_error(plist, pname, last_error);
1113       }
1114     }
1115     else if (rc < 0) last_error = rc;
1116   }
1117 
1118   /* PCL initialization string 1 */
1119   rc = fetch_octets(epref, plist, "PCLInit1", &data->init1);
1120   if (rc < 0) last_error = rc;
1121 
1122   /* PCL initialization string 2 */
1123   rc = fetch_octets(epref, plist, "PCLInit2", &data->init2);
1124   if (rc < 0) last_error = rc;
1125 
1126   /* PJL job name */
1127   rc = fetch_cstring(epref, plist, "PJLJob", &data->PJL_job);
1128   if (rc < 0) last_error = rc;
1129 
1130   /* PJL language */
1131   rc = fetch_cstring(epref, plist, "PJLLanguage", &data->PJL_language);
1132   if (rc < 0) last_error = rc;
1133 
1134   /* Print Quality */
1135   if ((rc = param_read_string(plist, (pname = "PrintQuality"), &string_value))
1136       == 0) {
1137     /*  The only known values are -1, 0 and 1. Again, however, we assume the
1138 	user knows what s/he is doing if another value is given. */
1139     rc = get_int_for_string(&string_value, print_quality_list, &temp);
1140     if (rc != 0) {
1141       if (rc != gs_error_VMerror) {
1142 	eprintf1("%s" ERRPREF "Unknown print quality: `", epref);
1143 	errwrite(string_value.data, sizeof(char)*string_value.size);
1144 	eprintf("'.\n");
1145       }
1146       last_error = rc;
1147       param_signal_error(plist, pname, last_error);
1148     }
1149     else {
1150       new_quality = true;
1151       if (temp < -1 || 1 < temp)
1152 	eprintf2("%s" WARNPREF "Unknown print quality: %d.\n",
1153 	  wpref, temp);
1154       pcl3_set_printquality(data, temp);
1155     }
1156   }
1157   else if (rc < 0) last_error = rc;
1158 
1159   /* Raster Graphics Quality */
1160   if ((rc = param_read_null(plist, (pname = "RasterGraphicsQuality"))) == 0)
1161     ;	/* ignore */
1162   else if (rc  < 0 &&
1163       (rc = param_read_int(plist, (pname = "RasterGraphicsQuality"), &temp))
1164 	== 0) {
1165     if (0 <= temp && temp <= 2) requested.quality = temp;
1166     else {
1167       eprintf2(
1168 	"%s" ERRPREF "Invalid value for raster graphics quality: %d.\n",
1169 	epref, temp);
1170       last_error = gs_error_rangecheck;
1171       param_signal_error(plist, pname, last_error);
1172     }
1173   }
1174   else if (rc < 0) last_error = rc;
1175 
1176   /* Colorant order */
1177   {
1178     bool temp;
1179     if ((rc = param_read_bool(plist, (pname = "SendBlackLast"), &temp)) == 0)
1180       data->order_CMYK = temp;
1181     else if (rc < 0 ) last_error = rc;
1182   }
1183 
1184   /* Sending of NULs */
1185   if ((rc = param_read_int(plist, (pname = "SendNULs"), &temp)) == 0) {
1186     if (data->NULs_to_send >= 0) data->NULs_to_send = temp;
1187     else {
1188       eprintf2(
1189 	"%s" ERRPREF "Invalid value for SendNULs parameter: %d.\n",
1190 	epref, temp);
1191       last_error = gs_error_rangecheck;
1192       param_signal_error(plist, pname, last_error);
1193     }
1194   }
1195   else if (rc < 0 ) last_error = rc;
1196 
1197   /* Shingling */
1198   if ((rc = param_read_null(plist, (pname = "Shingling"))) == 0)
1199     ;	/* ignore */
1200   else if (rc  < 0 &&
1201       (rc = param_read_int(plist, pname, &temp)) == 0) {
1202     if (0 <= temp && temp <= 2) requested.shingling = temp;
1203     else {
1204       eprintf2("%s" ERRPREF "Invalid value for shingling: %d.\n",
1205 	epref, temp);
1206       last_error = gs_error_rangecheck;
1207       param_signal_error(plist, pname, last_error);
1208     }
1209   }
1210   else if (rc < 0) last_error = rc;
1211 
1212   /* Tumble */
1213   if (is_generic_device(dev))
1214     if ((rc = param_read_bool(plist, (pname = "Tumble"), &dev->tumble)) < 0)
1215       last_error = rc;
1216 
1217   /* UseCard */
1218   {
1219     bool temp;
1220 
1221     if ((rc = param_read_null(plist, (pname = "UseCard"))) == 0)
1222       dev->use_card = bn_null;
1223     else if (rc < 0 &&
1224 	(rc = param_read_bool(plist, pname, &temp)) == 0)
1225       dev->use_card = (temp? bn_true: bn_false);
1226     else if (rc < 0 ) last_error = rc;
1227   }
1228 
1229   /* Process parameters defined by base classes (should occur after treating
1230      parameters defined for the derived class, see gsparam.h) */
1231   if ((rc = eprn_put_params(device, plist)) < 0 ||
1232     rc > 0 && last_error >= 0) last_error = rc;
1233 
1234   /* Act if the colour model was changed */
1235   if (previous_colour_model != dev->eprn.colour_model) set_palette(dev);
1236 
1237   if (last_error < 0) return_error(last_error);
1238 
1239   /* If we have seen new quality parameters, derive the old ones from them
1240      based on the current and possibly new value of the palette. */
1241   if (new_quality) pcl3_set_oldquality(data);
1242 
1243   /* If we have seen old quality parameters, store them */
1244   if (pcl_use_oldquality(data->level)) {
1245     if (requested.depletion >= 0) data->depletion = requested.depletion;
1246     if (requested.quality >= 0)
1247       data->raster_graphics_quality = requested.quality;
1248     if (requested.shingling >= 0) data->shingling = requested.shingling;
1249   }
1250 
1251   return 0;
1252 }
1253 
1254 /******************************************************************************
1255 
1256   Function: pcl3_open_device
1257 
1258 ******************************************************************************/
1259 
pcl3_open_device(gx_device * device)1260 static int pcl3_open_device(gx_device *device)
1261 {
1262   pcl3_Device *dev = (pcl3_Device *)device;
1263   const char
1264     *epref = dev->eprn.CUPS_messages? CUPS_ERRPREF: "",
1265     *wpref = dev->eprn.CUPS_messages? CUPS_WARNPREF: "";
1266   int rc;
1267 
1268   /* Constructor */
1269   if (!dev->initialized) init(dev);
1270 
1271 #ifdef PCL3_MEDIA_FILE
1272   /* Change default media descriptions for 'unspec' */
1273   if (dev->eprn.media_file == NULL && dev->printer == pcl3_generic_new) {
1274     if ((rc = eprn_set_media_data(device, PCL3_MEDIA_FILE, 0)) != 0)
1275       return rc;
1276   }
1277 #endif
1278 
1279   /* Check on rendering parameters */
1280   if ((dev->eprn.black_levels > 2 || dev->eprn.non_black_levels > 2) &&
1281       dev->file_data.print_quality == -1)
1282     eprintf2(
1283       "%s" WARNPREF "More than 2 intensity levels and draft quality\n"
1284       "%s    are unlikely to work in combination.\n", wpref, wpref);
1285 
1286   /* Ensure correct media request flags */
1287   eprn_set_media_flags((eprn_Device *)dev,
1288     (dev->file_data.media_source == -1? MS_BIG_FLAG: ms_none) |
1289       (dev->use_card == bn_true? PCL_CARD_FLAG: ms_none),
1290     (dev->use_card == bn_null? card_is_optional: NULL));
1291 
1292   dev->eprn.soft_tumble = false;
1293 
1294   /* Open the "eprn" device part */
1295   if ((rc = eprn_open_device(device)) != 0) return rc;
1296 
1297   /* Fill the still unassigned parts of 'file_data' from the other data */
1298   {
1299     pcl_FileData *data = &dev->file_data;
1300     unsigned int j;
1301 
1302     /* Media handling */
1303     data->size = pcl3_page_size(dev->eprn.code);
1304     if (data->size == pcl_ps_default) {
1305       /*  This is due to a media description using a media size code for which
1306 	  there is no PCL Page Size code. This is either an error in a builtin
1307 	  description or the user specified it in a media configuration file.
1308 	  Note that there might be a "Card" flag, hence we should not talk
1309 	  about "size" only.
1310       */
1311       char buffer[50];
1312 
1313       eprintf2("%s" ERRPREF
1314 	"The current configuration for this driver has identified the\n"
1315 	"%s  page setup requested by the document as being for `",
1316 	epref, epref);
1317       if (ms_find_name_from_code(buffer, sizeof(buffer),
1318 	  dev->eprn.code, flag_description) == 0) eprintf1("%s", buffer);
1319       else eprintf("UNKNOWN");	/* should never happen */
1320       eprintf3("' (%.0f x %.0f bp).\n"
1321 	"%s  The driver does not know how to do this in PCL.\n",
1322 	dev->MediaSize[0], dev->MediaSize[1], epref);
1323       if (dev->eprn.media_file != NULL)
1324 	eprintf2(
1325 	  "%s  You should therefore not include such an entry in the\n"
1326 	  "%s  media configuration file.\n", epref, epref);
1327       return_error(gs_error_rangecheck);
1328     }
1329     data->duplex = -1;
1330     if (dev->Duplex_set > 0) {	/* Duplex is not null */
1331       if (dev->Duplex) {
1332 	bool same_leading_edge;
1333 
1334 	/* Find direction of default user space y axis in device space */
1335 	int orient = dev->eprn.default_orientation;
1336 	if (dev->MediaSize[1] < dev->MediaSize[0]) /* landscape */
1337 	  orient++;	/* rotate +90 degrees */
1338 
1339 	same_leading_edge = (orient % 2 == 0  /* y axis is vertical */) !=
1340 	  (dev->tumble != false);
1341 	  /* If there were a native 'bool' type in C, the last parenthesis
1342 	     could be reliably replaced by "dev->tumble". This is safer and
1343 	     just as fast, provided the compiler is sufficiently intelligent. */
1344 
1345 	dev->eprn.soft_tumble = dev->duplex_capability != Duplex_both &&
1346 	    (same_leading_edge &&
1347 		dev->duplex_capability != Duplex_sameLeadingEdge ||
1348 	      !same_leading_edge &&
1349 		dev->duplex_capability != Duplex_oppositeLeadingEdge);
1350 	if (dev->eprn.soft_tumble) same_leading_edge = !same_leading_edge;
1351 
1352 	/*  I am assuming here that the values 1 and 2, specified by HP in
1353 	    BPL02705 as meaning "Long-Edge Binding" and "Short-Edge Binding",
1354 	    respectively, in fact mean what I've called the "same leading edge"
1355 	    and "opposite leading edge" settings for the second pass. */
1356 	if (same_leading_edge) data->duplex = 1;
1357 	else data->duplex = 2;
1358       }
1359       else data->duplex = 0;			/* simplex */
1360     }
1361 
1362     /* It is almost not necessary to set the palette here because the default
1363        settings of eprn and pcl3 agree and all other calls are routed through
1364        the put_params routines. But there is a special case: I want to use
1365        'pcl_no_palette' if the printer cannot switch palettes. */
1366     set_palette(dev);
1367 
1368     /* Per-colorant information */
1369     for (j = 0; j < data->number_of_colorants; j++) {
1370       data->colorant_array[j].hres = dev->HWResolution[0] + 0.5;
1371       data->colorant_array[j].vres = dev->HWResolution[1] + 0.5;
1372     }
1373     if (data->palette == pcl_CMY || data->palette == pcl_RGB)
1374       for (j = 0; j < 3; j++)
1375 	data->colorant_array[j].levels = dev->eprn.non_black_levels;
1376     else {
1377       data->colorant_array[0].levels = dev->eprn.black_levels;
1378       for (j = 1; j < data->number_of_colorants; j++)
1379 	data->colorant_array[j].levels = dev->eprn.non_black_levels;
1380     }
1381   }
1382 
1383   return rc;
1384 }
1385 
1386 /******************************************************************************
1387 
1388   Function: pcl3_close_device
1389 
1390 ******************************************************************************/
1391 
pcl3_close_device(gx_device * device)1392 static int pcl3_close_device(gx_device *device)
1393 {
1394   pcl3_Device *dev = (pcl3_Device *)device;
1395 
1396   /*  HP recommends that a driver should send the Printer Reset command at the
1397       end of each print job in order to leave the printer in its default state.
1398       This is a matter of courtesy for the next print job which could otherwise
1399       inherit some of the properties set for the present job unless it starts
1400       with a Printer Reset command itself (every job generated with this driver
1401       does).
1402 
1403       Unfortunately, ghostscript does not have a corresponding device procedure.
1404       In particular, the 'close_device' procedure may be called multiple times
1405       during a job and for multi-file output it is even only called at the end
1406       of the sequence of files and then when 'dev->file' is already NULL.
1407       Hence this routine tries to get close by checking the 'configured' field:
1408       it is set if the pcl3_init_file() function has been called and therefore
1409       indicates that the driver has sent configuration commands to the printer.
1410       That part we can and should take back.
1411 
1412       Of course one might reset the printer at the end of every page, but this
1413       would entail having to repeat the initialization at the beginning of
1414       every page. I regard this as logically inappropriate.
1415   */
1416 
1417   if (dev->configured && dev->file != NULL) {
1418     pcl3_end_file(dev->file, &dev->file_data);
1419     dev->configured = false;
1420   }
1421 
1422   return eprn_close_device(device);
1423 }
1424 
1425 /******************************************************************************
1426 
1427   Function: pcl3_print_page
1428 
1429   This is the implementation of prn's print_page() method for this device.
1430 
1431   It initializes the printer if necessary and prints the page.
1432 
1433 ******************************************************************************/
1434 
1435 /* Macro to handle return codes from calls to pclgen routines */
1436 #define guard(call)							\
1437     if ((rc = (call)) != 0) {						\
1438       if (rc > 0) return_error(gs_error_Fatal); /* bugs are fatal :-) */ \
1439       return_error(gs_error_ioerror);	/* actually any environment error */ \
1440     }
1441 
pcl3_print_page(gx_device_printer * device,FILE * out)1442 static int pcl3_print_page(gx_device_printer *device, FILE *out)
1443 {
1444   int
1445     blank_lines,
1446     rc;
1447   pcl3_Device *dev = (pcl3_Device *)device;
1448   const char *epref = dev->eprn.CUPS_messages? CUPS_ERRPREF: "";
1449   pcl_RasterData rd;
1450   unsigned int
1451     j,
1452     *lengths,
1453     planes;
1454 
1455   /* If this is a new file or we've decided to re-configure, initialize the
1456      printer first */
1457   if (gdev_prn_file_is_new(device) || !dev->configured ||
1458       dev->configure_every_page) {
1459     guard(pcl3_init_file(out, &dev->file_data))
1460     dev->configured = true;
1461   }
1462 
1463   /* Initialize raster data structure */
1464   memset(&rd, 0, sizeof(pcl_RasterData));
1465   rd.global = &dev->file_data;
1466   planes = eprn_number_of_bitplanes((eprn_Device *)dev);
1467   lengths = (unsigned int *)malloc(planes*sizeof(unsigned int));
1468   rd.next = (pcl_OctetString *)malloc(planes*sizeof(pcl_OctetString));
1469   if (pcl_cm_is_differential(dev->file_data.compression))
1470     rd.previous = (pcl_OctetString *)malloc(planes*sizeof(pcl_OctetString));
1471   if (lengths == NULL || rd.next == NULL ||
1472       pcl_cm_is_differential(dev->file_data.compression) &&
1473 	rd.previous == NULL) {
1474     free(lengths); free(rd.next); free(rd.previous);
1475     eprintf1("%s" ERRPREF "Memory allocation failure from malloc().\n",
1476       epref);
1477     return_error(gs_error_VMerror);
1478   }
1479   eprn_number_of_octets((eprn_Device *)dev, lengths);
1480   rd.width = 8*lengths[0];	/* all colorants have equal resolution */
1481   for (j = 0; j < planes; j++)
1482     rd.next[j].str = (pcl_Octet *)malloc(lengths[j]*sizeof(eprn_Octet));
1483     /* Note: 'pcl_Octet' must be identical with 'eprn_Octet'. */
1484   if (pcl_cm_is_differential(dev->file_data.compression))
1485     for (j = 0; j < planes; j++)
1486       rd.previous[j].str = (pcl_Octet *)malloc(lengths[j]*sizeof(eprn_Octet));
1487   rd.workspace_allocated = lengths[0];
1488   for (j = 1; j < planes; j++)
1489     if (lengths[j] > rd.workspace_allocated)
1490       rd.workspace_allocated = lengths[j];
1491   for (j = 0;
1492       j < 2 && (j != 1 || dev->file_data.compression == pcl_cm_delta); j++)
1493     rd.workspace[j] =
1494       (pcl_Octet *)malloc(rd.workspace_allocated*sizeof(pcl_Octet));
1495 
1496   /* Collective check for allocation failures */
1497   j = 0;
1498   while (j < planes && rd.next[j].str != NULL) j++;
1499   if (j == planes && pcl_cm_is_differential(dev->file_data.compression)) {
1500     j = 0;
1501     while (j < planes && rd.previous[j].str != NULL) j++;
1502     if (j == planes && dev->file_data.compression == pcl_cm_delta &&
1503 	rd.workspace[1] == NULL) j = 0;
1504   }
1505   if (j < planes || rd.workspace[0] == NULL) {
1506     /* Free everything. Note that free(NULL) is legal and we did a memset()
1507        with 0 on 'rd'. */
1508     for (j = 0; j < planes; j++) {
1509       free(rd.next[j].str);
1510       if (pcl_cm_is_differential(dev->file_data.compression))
1511 	free(rd.previous[j].str);
1512     }
1513     free(lengths); free(rd.next); free(rd.previous);
1514     for (j = 0; j < 2; j++) free(rd.workspace[j]);
1515 
1516     eprintf1("%s" ERRPREF "Memory allocation failure from malloc().\n",
1517       epref);
1518     return_error(gs_error_VMerror);
1519   }
1520 
1521   /* Open the page and start raster mode */
1522   guard(pcl3_begin_page(out, &dev->file_data))
1523   guard(pcl3_begin_raster(out, &rd))
1524 
1525   /* Loop over scan lines */
1526   blank_lines = 0;
1527   while (eprn_get_planes((eprn_Device *)dev, (eprn_OctetString *)rd.next) == 0){
1528     /* Is this a blank (white) line? */
1529     if (dev->eprn.colour_model == eprn_DeviceRGB) {
1530       /*  White results if all three colorants use their highest intensity.
1531 	  Fortunately, PCL-3+ can only support two intensity levels for all
1532 	  colorants in an RGB palette, hence this intensity must be one for all
1533 	  colorants simultaneously.
1534 	  Because the planes returned by eprn_get_planes() are guaranteed to
1535 	  have no trailing zero octets, we can easily check that they are of
1536 	  equal length before proceeding further.
1537       */
1538       for (j = 1; j < planes && rd.next[j].length == rd.next[0].length; j++);
1539       if (j >= planes && rd.next[0].length == lengths[0]) {
1540 	int k;
1541 	/* All planes have the same length and cover the whole width of the
1542 	   page. Check that they all contain 0xFF. */
1543 	j = 0;
1544 	do {
1545 	  k = rd.next[j].length - 1;
1546 	  while (k > 0 && rd.next[j].str[k] == 0xFF) k--;
1547 	} while (k == 0 && rd.next[j].str[0] == 0xFF && ++j < planes);
1548       }
1549     }
1550     else
1551       /* White is zero */
1552       for (j = 0; j < planes && rd.next[j].length == 0; j++);
1553 
1554     if (j == planes) blank_lines++;
1555     else {
1556       if (blank_lines > 0) {
1557 	guard(pcl3_skip_groups(out, &rd, blank_lines))
1558 	blank_lines = 0;
1559       }
1560       guard(pcl3_transfer_group(out, &rd))
1561     }
1562   }
1563 
1564   /* Terminate raster mode and close the page */
1565   guard(pcl3_end_raster(out, &rd))
1566   guard(pcl3_end_page(out, &dev->file_data))
1567 
1568   /* Free dynamic storage */
1569   for (j = 0; j < planes; j++) free(rd.next[j].str);
1570   if (pcl_cm_is_differential(dev->file_data.compression))
1571     for (j = 0; j < planes; j++) free(rd.previous[j].str);
1572   for (j = 0; j < 2; j++) free(rd.workspace[j]);
1573   free(lengths); free(rd.next); free(rd.previous);
1574 
1575   return 0;
1576 }
1577 
1578 #undef guard
1579