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