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(dev->memory,
911                  string_value.data, sizeof(char)*string_value.size);
912         eprintf("'.\n");
913         last_error = gs_error_rangecheck;
914         param_signal_error(plist, pname, last_error);
915       }
916     }
917     else if (rc < 0) last_error = rc;
918   }
919 
920   /* Constructor */
921   if (!dev->initialized) init(dev);
922 
923   /* Compression method */
924   if ((rc = param_read_int(plist, (pname = "CompressionMethod"), &temp))
925       == 0) {
926     if (temp != pcl_cm_none && temp != pcl_cm_rl && temp != pcl_cm_tiff &&
927         temp != pcl_cm_delta && temp != pcl_cm_crdr) {
928       eprintf2("%s" ERRPREF "Unsupported compression method: %d.\n",
929         epref, temp);
930       last_error = gs_error_rangecheck;
931       param_signal_error(plist, pname, last_error);
932     }
933     else {
934       if (temp == pcl_cm_crdr && (dev->printer == HPDeskJet ||
935           dev->printer == HPDeskJetPlus || dev->printer == HPDJ500)) {
936         /* This I know to be the case for the DJ 500. The others are guessed. */
937         eprintf2(
938           "%s" ERRPREF "The %s does not support compression method 9.\n",
939           epref, dev->eprn.cap->name);
940         last_error = gs_error_rangecheck;
941         param_signal_error(plist, pname, last_error);
942       }
943       else data->compression= temp;
944     }
945   }
946   else if (rc < 0) last_error = rc;
947 
948   /* Configure every page */
949   if ((rc = param_read_bool(plist, "ConfigureEveryPage",
950     &dev->configure_every_page)) < 0) last_error = rc;
951 
952   /* Depletion */
953   if ((rc = param_read_null(plist, (pname = "Depletion"))) == 0)
954     requested.depletion = 0;
955   else if (rc < 0 && (rc = param_read_int(plist, pname, &temp)) == 0) {
956     if (1 <= temp && temp <= 5 && (dev->printer != HPDJ500C || temp <= 3))
957       requested.depletion = temp;
958     else {
959       eprintf2("%s" ERRPREF "Invalid value for depletion: %d.\n",
960         epref, temp);
961       last_error = gs_error_rangecheck;
962       param_signal_error(plist, pname, last_error);
963     }
964   }
965   else if (rc < 0) last_error = rc;
966 
967   /* Dry time */
968   if ((rc = param_read_null(plist, (pname = "DryTime"))) == 0)
969     data->dry_time = -1;
970   else if (rc < 0 &&
971       (rc = param_read_int(plist, pname, &temp)) == 0) {
972     if (0 <= temp && temp <= 1200) {
973       if (dev->printer == HPDJ500 || dev->printer == HPDJ500C) {
974          /* According to HP (DJ6/8 p. 18), only some of the series 600 and 800
975             DeskJets respond to this command. I also suspect that the same is
976             true for pre-DeskJet-500 printers. This should not matter, though,
977             because the PCL interpreter should merely ignore the command.
978             Hence I'm giving an error message only in those cases where HP
979             explicitly states that the printer does not support the command.
980           */
981         eprintf2(
982           "%s" ERRPREF "The %s does not support setting a dry time.\n",
983           epref, dev->eprn.cap->name);
984         last_error = gs_error_rangecheck;
985         param_signal_error(plist, pname, last_error);
986       }
987       else data->dry_time = temp;
988     }
989     else {
990       eprintf2("%s" ERRPREF "Invalid value for the dry time: %d.\n",
991         epref, temp);
992       last_error = gs_error_rangecheck;
993       param_signal_error(plist, pname, last_error);
994     }
995   }
996   else if (rc < 0) last_error = rc;
997 
998   /* Duplex capability */
999   if (is_generic_device(dev)) {
1000     if ((rc = param_read_string(plist, (pname = "DuplexCapability"),
1001         &string_value)) == 0) {
1002       rc = eprn_get_int(&string_value, duplex_capabilities_list, &temp);
1003       if (rc == 0) {
1004         if (dev->printer == pcl3_generic_new ||
1005             dev->printer == pcl3_generic_old || temp == Duplex_none) {
1006           dev->duplex_capability = temp;
1007           if (dev->duplex_capability == Duplex_none)
1008             dev->Duplex_set = 0;        /* force to "null" */
1009         }
1010         else {
1011           eprintf2("%s" ERRPREF
1012             "You can use a non-trivial value for DuplexCapability\n"
1013             "%s  only for unspec and unspecold.\n", epref, epref);
1014           last_error = gs_error_rangecheck;
1015           param_signal_error(plist, pname, last_error);
1016         }
1017       }
1018       else {
1019         eprintf1("%s" ERRPREF "Invalid duplex capability: `", epref);
1020         errwrite(dev->memory,
1021                  string_value.data, 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                  string_value.data, sizeof(char)*string_value.size);
1078         eprintf("'.\n");
1079       }
1080       last_error = rc;
1081       param_signal_error(plist, pname, last_error);
1082     }
1083     else {
1084       new_quality = true;
1085       if (temp < 0 || 6 < temp)
1086         eprintf2("%s" WARNPREF "Unknown media type code: %d.\n",
1087           wpref, temp);
1088       pcl3_set_mediatype(data, temp);
1089     }
1090   }
1091   else if (rc < 0) last_error = rc;
1092 
1093   /* Media destination */
1094   if ((rc = param_read_int(plist, (pname = "%MediaDestination"),
1095     &data->media_destination)) < 0) last_error = rc;
1096 
1097   /* Media source */
1098   if ((rc = param_read_int(plist, (pname = "%MediaSource"),
1099     &data->media_source)) < 0) last_error = rc;
1100   else if (rc == 0 && dev->is_open) gs_closedevice(device);
1101     /* In pcl3, %MediaSource is relevant for banner printing and hence page
1102        layout which is determined in the open routine. */
1103 
1104   /* Use of Configure Raster Data */
1105   if (is_generic_device(dev) || pcl_has_CRD(data->level)) {
1106     bool temp;
1107 
1108     if ((rc = param_read_bool(plist, (pname = "OnlyCRD"), &temp)) == 0) {
1109       if (pcl_has_CRD(data->level))
1110         data->level = (temp? pcl_level_3plus_CRD_only: pcl_level_3plus_S68);
1111       else if (temp == true) {
1112         eprintf1("%s" ERRPREF
1113           "OnlyCRD may be set only for group-3 devices.\n", epref);
1114         last_error = gs_error_rangecheck;
1115         param_signal_error(plist, pname, last_error);
1116       }
1117     }
1118     else if (rc < 0) last_error = rc;
1119   }
1120 
1121   /* PCL initialization string 1 */
1122   rc = fetch_octets(epref, plist, "PCLInit1", &data->init1);
1123   if (rc < 0) last_error = rc;
1124 
1125   /* PCL initialization string 2 */
1126   rc = fetch_octets(epref, plist, "PCLInit2", &data->init2);
1127   if (rc < 0) last_error = rc;
1128 
1129   /* PJL job name */
1130   rc = fetch_cstring(epref, plist, "PJLJob", &data->PJL_job);
1131   if (rc < 0) last_error = rc;
1132 
1133   /* PJL language */
1134   rc = fetch_cstring(epref, plist, "PJLLanguage", &data->PJL_language);
1135   if (rc < 0) last_error = rc;
1136 
1137   /* Print Quality */
1138   if ((rc = param_read_string(plist, (pname = "PrintQuality"), &string_value))
1139       == 0) {
1140     /*  The only known values are -1, 0 and 1. Again, however, we assume the
1141         user knows what s/he is doing if another value is given. */
1142     rc = get_int_for_string(&string_value, print_quality_list, &temp);
1143     if (rc != 0) {
1144       if (rc != gs_error_VMerror) {
1145         eprintf1("%s" ERRPREF "Unknown print quality: `", epref);
1146         errwrite(dev->memory,
1147                  string_value.data, sizeof(char)*string_value.size);
1148         eprintf("'.\n");
1149       }
1150       last_error = rc;
1151       param_signal_error(plist, pname, last_error);
1152     }
1153     else {
1154       new_quality = true;
1155       if (temp < -1 || 1 < temp)
1156         eprintf2("%s" WARNPREF "Unknown print quality: %d.\n",
1157           wpref, temp);
1158       pcl3_set_printquality(data, temp);
1159     }
1160   }
1161   else if (rc < 0) last_error = rc;
1162 
1163   /* Raster Graphics Quality */
1164   if ((rc = param_read_null(plist, (pname = "RasterGraphicsQuality"))) == 0)
1165     ;   /* ignore */
1166   else if (rc  < 0 &&
1167       (rc = param_read_int(plist, (pname = "RasterGraphicsQuality"), &temp))
1168         == 0) {
1169     if (0 <= temp && temp <= 2) requested.quality = temp;
1170     else {
1171       eprintf2(
1172         "%s" ERRPREF "Invalid value for raster graphics quality: %d.\n",
1173         epref, temp);
1174       last_error = gs_error_rangecheck;
1175       param_signal_error(plist, pname, last_error);
1176     }
1177   }
1178   else if (rc < 0) last_error = rc;
1179 
1180   /* Colorant order */
1181   {
1182     bool temp;
1183     if ((rc = param_read_bool(plist, (pname = "SendBlackLast"), &temp)) == 0)
1184       data->order_CMYK = temp;
1185     else if (rc < 0 ) last_error = rc;
1186   }
1187 
1188   /* Sending of NULs */
1189   if ((rc = param_read_int(plist, (pname = "SendNULs"), &temp)) == 0) {
1190     if (data->NULs_to_send >= 0) data->NULs_to_send = temp;
1191     else {
1192       eprintf2(
1193         "%s" ERRPREF "Invalid value for SendNULs parameter: %d.\n",
1194         epref, temp);
1195       last_error = gs_error_rangecheck;
1196       param_signal_error(plist, pname, last_error);
1197     }
1198   }
1199   else if (rc < 0 ) last_error = rc;
1200 
1201   /* Shingling */
1202   if ((rc = param_read_null(plist, (pname = "Shingling"))) == 0)
1203     ;   /* ignore */
1204   else if (rc  < 0 &&
1205       (rc = param_read_int(plist, pname, &temp)) == 0) {
1206     if (0 <= temp && temp <= 2) requested.shingling = temp;
1207     else {
1208       eprintf2("%s" ERRPREF "Invalid value for shingling: %d.\n",
1209         epref, temp);
1210       last_error = gs_error_rangecheck;
1211       param_signal_error(plist, pname, last_error);
1212     }
1213   }
1214   else if (rc < 0) last_error = rc;
1215 
1216   /* Tumble */
1217   if (is_generic_device(dev))
1218     if ((rc = param_read_bool(plist, (pname = "Tumble"), &dev->tumble)) < 0)
1219       last_error = rc;
1220 
1221   /* UseCard */
1222   {
1223     bool temp;
1224 
1225     if ((rc = param_read_null(plist, (pname = "UseCard"))) == 0)
1226       dev->use_card = bn_null;
1227     else if (rc < 0 &&
1228         (rc = param_read_bool(plist, pname, &temp)) == 0)
1229       dev->use_card = (temp? bn_true: bn_false);
1230     else if (rc < 0 ) last_error = rc;
1231   }
1232 
1233   /* Process parameters defined by base classes (should occur after treating
1234      parameters defined for the derived class, see gsparam.h) */
1235   if ((rc = eprn_put_params(device, plist)) < 0 ||
1236     rc > 0 && last_error >= 0) last_error = rc;
1237 
1238   /* Act if the colour model was changed */
1239   if (previous_colour_model != dev->eprn.colour_model) set_palette(dev);
1240 
1241   if (last_error < 0) return_error(last_error);
1242 
1243   /* If we have seen new quality parameters, derive the old ones from them
1244      based on the current and possibly new value of the palette. */
1245   if (new_quality) pcl3_set_oldquality(data);
1246 
1247   /* If we have seen old quality parameters, store them */
1248   if (pcl_use_oldquality(data->level)) {
1249     if (requested.depletion >= 0) data->depletion = requested.depletion;
1250     if (requested.quality >= 0)
1251       data->raster_graphics_quality = requested.quality;
1252     if (requested.shingling >= 0) data->shingling = requested.shingling;
1253   }
1254 
1255   return 0;
1256 }
1257 
1258 /******************************************************************************
1259 
1260   Function: pcl3_open_device
1261 
1262 ******************************************************************************/
1263 
pcl3_open_device(gx_device * device)1264 static int pcl3_open_device(gx_device *device)
1265 {
1266   pcl3_Device *dev = (pcl3_Device *)device;
1267   const char
1268     *epref = dev->eprn.CUPS_messages? CUPS_ERRPREF: "",
1269     *wpref = dev->eprn.CUPS_messages? CUPS_WARNPREF: "";
1270   int rc;
1271 
1272   /* Constructor */
1273   if (!dev->initialized) init(dev);
1274 
1275 #ifdef PCL3_MEDIA_FILE
1276   /* Change default media descriptions for 'unspec' */
1277   if (dev->eprn.media_file == NULL && dev->printer == pcl3_generic_new) {
1278     if ((rc = eprn_set_media_data(device, PCL3_MEDIA_FILE, 0)) != 0)
1279       return rc;
1280   }
1281 #endif
1282 
1283   /* Check on rendering parameters */
1284   if ((dev->eprn.black_levels > 2 || dev->eprn.non_black_levels > 2) &&
1285       dev->file_data.print_quality == -1)
1286     eprintf2(
1287       "%s" WARNPREF "More than 2 intensity levels and draft quality\n"
1288       "%s    are unlikely to work in combination.\n", wpref, wpref);
1289 
1290   /* Ensure correct media request flags */
1291   eprn_set_media_flags((eprn_Device *)dev,
1292     (dev->file_data.media_source == -1? MS_BIG_FLAG: ms_none) |
1293       (dev->use_card == bn_true? PCL_CARD_FLAG: ms_none),
1294     (dev->use_card == bn_null? card_is_optional: NULL));
1295 
1296   dev->eprn.soft_tumble = false;
1297 
1298   /* Open the "eprn" device part */
1299   if ((rc = eprn_open_device(device)) != 0) return rc;
1300 
1301   /* Fill the still unassigned parts of 'file_data' from the other data */
1302   {
1303     pcl_FileData *data = &dev->file_data;
1304     unsigned int j;
1305 
1306     /* Media handling */
1307     data->size = pcl3_page_size(dev->eprn.code);
1308     if (data->size == pcl_ps_default) {
1309       /*  This is due to a media description using a media size code for which
1310           there is no PCL Page Size code. This is either an error in a builtin
1311           description or the user specified it in a media configuration file.
1312           Note that there might be a "Card" flag, hence we should not talk
1313           about "size" only.
1314       */
1315       char buffer[50];
1316 
1317       eprintf2("%s" ERRPREF
1318         "The current configuration for this driver has identified the\n"
1319         "%s  page setup requested by the document as being for `",
1320         epref, epref);
1321       if (ms_find_name_from_code(buffer, sizeof(buffer),
1322           dev->eprn.code, flag_description) == 0) eprintf1("%s", buffer);
1323       else eprintf("UNKNOWN");  /* should never happen */
1324       eprintf3("' (%.0f x %.0f bp).\n"
1325         "%s  The driver does not know how to do this in PCL.\n",
1326         dev->MediaSize[0], dev->MediaSize[1], epref);
1327       if (dev->eprn.media_file != NULL)
1328         eprintf2(
1329           "%s  You should therefore not include such an entry in the\n"
1330           "%s  media configuration file.\n", epref, epref);
1331       return_error(gs_error_rangecheck);
1332     }
1333     data->duplex = -1;
1334     if (dev->Duplex_set > 0) {  /* Duplex is not null */
1335       if (dev->Duplex) {
1336         bool same_leading_edge;
1337 
1338         /* Find direction of default user space y axis in device space */
1339         int orient = dev->eprn.default_orientation;
1340         if (dev->MediaSize[1] < dev->MediaSize[0]) /* landscape */
1341           orient++;     /* rotate +90 degrees */
1342 
1343         same_leading_edge = (orient % 2 == 0  /* y axis is vertical */) !=
1344           (dev->tumble != false);
1345           /* If there were a native 'bool' type in C, the last parenthesis
1346              could be reliably replaced by "dev->tumble". This is safer and
1347              just as fast, provided the compiler is sufficiently intelligent. */
1348 
1349         dev->eprn.soft_tumble = dev->duplex_capability != Duplex_both &&
1350             (same_leading_edge &&
1351                 dev->duplex_capability != Duplex_sameLeadingEdge ||
1352               !same_leading_edge &&
1353                 dev->duplex_capability != Duplex_oppositeLeadingEdge);
1354         if (dev->eprn.soft_tumble) same_leading_edge = !same_leading_edge;
1355 
1356         /*  I am assuming here that the values 1 and 2, specified by HP in
1357             BPL02705 as meaning "Long-Edge Binding" and "Short-Edge Binding",
1358             respectively, in fact mean what I've called the "same leading edge"
1359             and "opposite leading edge" settings for the second pass. */
1360         if (same_leading_edge) data->duplex = 1;
1361         else data->duplex = 2;
1362       }
1363       else data->duplex = 0;                    /* simplex */
1364     }
1365 
1366     /* It is almost not necessary to set the palette here because the default
1367        settings of eprn and pcl3 agree and all other calls are routed through
1368        the put_params routines. But there is a special case: I want to use
1369        'pcl_no_palette' if the printer cannot switch palettes. */
1370     set_palette(dev);
1371 
1372     /* Per-colorant information */
1373     for (j = 0; j < data->number_of_colorants; j++) {
1374       data->colorant_array[j].hres = dev->HWResolution[0] + 0.5;
1375       data->colorant_array[j].vres = dev->HWResolution[1] + 0.5;
1376     }
1377     if (data->palette == pcl_CMY || data->palette == pcl_RGB)
1378       for (j = 0; j < 3; j++)
1379         data->colorant_array[j].levels = dev->eprn.non_black_levels;
1380     else {
1381       data->colorant_array[0].levels = dev->eprn.black_levels;
1382       for (j = 1; j < data->number_of_colorants; j++)
1383         data->colorant_array[j].levels = dev->eprn.non_black_levels;
1384     }
1385   }
1386 
1387   return rc;
1388 }
1389 
1390 /******************************************************************************
1391 
1392   Function: pcl3_close_device
1393 
1394 ******************************************************************************/
1395 
pcl3_close_device(gx_device * device)1396 static int pcl3_close_device(gx_device *device)
1397 {
1398   pcl3_Device *dev = (pcl3_Device *)device;
1399 
1400   /*  HP recommends that a driver should send the Printer Reset command at the
1401       end of each print job in order to leave the printer in its default state.
1402       This is a matter of courtesy for the next print job which could otherwise
1403       inherit some of the properties set for the present job unless it starts
1404       with a Printer Reset command itself (every job generated with this driver
1405       does).
1406 
1407       Unfortunately, ghostscript does not have a corresponding device procedure.
1408       In particular, the 'close_device' procedure may be called multiple times
1409       during a job and for multi-file output it is even only called at the end
1410       of the sequence of files and then when 'dev->file' is already NULL.
1411       Hence this routine tries to get close by checking the 'configured' field:
1412       it is set if the pcl3_init_file() function has been called and therefore
1413       indicates that the driver has sent configuration commands to the printer.
1414       That part we can and should take back.
1415 
1416       Of course one might reset the printer at the end of every page, but this
1417       would entail having to repeat the initialization at the beginning of
1418       every page. I regard this as logically inappropriate.
1419   */
1420 
1421   if (dev->configured && dev->file != NULL) {
1422     pcl3_end_file(dev->file, &dev->file_data);
1423     dev->configured = false;
1424   }
1425 
1426   return eprn_close_device(device);
1427 }
1428 
1429 /******************************************************************************
1430 
1431   Function: pcl3_print_page
1432 
1433   This is the implementation of prn's print_page() method for this device.
1434 
1435   It initializes the printer if necessary and prints the page.
1436 
1437 ******************************************************************************/
1438 
1439 /* Macro to handle return codes from calls to pclgen routines */
1440 #define guard(call)                                                     \
1441     if ((rc = (call)) != 0) {                                           \
1442       if (rc > 0) return_error(gs_error_Fatal); /* bugs are fatal :-) */ \
1443       return_error(gs_error_ioerror);   /* actually any environment error */ \
1444     }
1445 
pcl3_print_page(gx_device_printer * device,FILE * out)1446 static int pcl3_print_page(gx_device_printer *device, FILE *out)
1447 {
1448   int
1449     blank_lines,
1450     rc;
1451   pcl3_Device *dev = (pcl3_Device *)device;
1452   const char *epref = dev->eprn.CUPS_messages? CUPS_ERRPREF: "";
1453   pcl_RasterData rd;
1454   unsigned int
1455     j,
1456     *lengths,
1457     planes;
1458 
1459   /* If this is a new file or we've decided to re-configure, initialize the
1460      printer first */
1461   if (gdev_prn_file_is_new(device) || !dev->configured ||
1462       dev->configure_every_page) {
1463     guard(pcl3_init_file(out, &dev->file_data))
1464     dev->configured = true;
1465   }
1466 
1467   /* Initialize raster data structure */
1468   memset(&rd, 0, sizeof(pcl_RasterData));
1469   rd.global = &dev->file_data;
1470   planes = eprn_number_of_bitplanes((eprn_Device *)dev);
1471   lengths = (unsigned int *)malloc(planes*sizeof(unsigned int));
1472   rd.next = (pcl_OctetString *)malloc(planes*sizeof(pcl_OctetString));
1473   if (pcl_cm_is_differential(dev->file_data.compression))
1474     rd.previous = (pcl_OctetString *)malloc(planes*sizeof(pcl_OctetString));
1475   if (lengths == NULL || rd.next == NULL ||
1476       pcl_cm_is_differential(dev->file_data.compression) &&
1477         rd.previous == NULL) {
1478     free(lengths); free(rd.next); free(rd.previous);
1479     eprintf1("%s" ERRPREF "Memory allocation failure from malloc().\n",
1480       epref);
1481     return_error(gs_error_VMerror);
1482   }
1483   eprn_number_of_octets((eprn_Device *)dev, lengths);
1484   rd.width = 8*lengths[0];      /* all colorants have equal resolution */
1485   for (j = 0; j < planes; j++)
1486     rd.next[j].str = (pcl_Octet *)malloc(lengths[j]*sizeof(eprn_Octet));
1487     /* Note: 'pcl_Octet' must be identical with 'eprn_Octet'. */
1488   if (pcl_cm_is_differential(dev->file_data.compression))
1489     for (j = 0; j < planes; j++)
1490       rd.previous[j].str = (pcl_Octet *)malloc(lengths[j]*sizeof(eprn_Octet));
1491   rd.workspace_allocated = lengths[0];
1492   for (j = 1; j < planes; j++)
1493     if (lengths[j] > rd.workspace_allocated)
1494       rd.workspace_allocated = lengths[j];
1495   for (j = 0;
1496       j < 2 && (j != 1 || dev->file_data.compression == pcl_cm_delta); j++)
1497     rd.workspace[j] =
1498       (pcl_Octet *)malloc(rd.workspace_allocated*sizeof(pcl_Octet));
1499 
1500   /* Collective check for allocation failures */
1501   j = 0;
1502   while (j < planes && rd.next[j].str != NULL) j++;
1503   if (j == planes && pcl_cm_is_differential(dev->file_data.compression)) {
1504     j = 0;
1505     while (j < planes && rd.previous[j].str != NULL) j++;
1506     if (j == planes && dev->file_data.compression == pcl_cm_delta &&
1507         rd.workspace[1] == NULL) j = 0;
1508   }
1509   if (j < planes || rd.workspace[0] == NULL) {
1510     /* Free everything. Note that free(NULL) is legal and we did a memset()
1511        with 0 on 'rd'. */
1512     for (j = 0; j < planes; j++) {
1513       free(rd.next[j].str);
1514       if (pcl_cm_is_differential(dev->file_data.compression))
1515         free(rd.previous[j].str);
1516     }
1517     free(lengths); free(rd.next); free(rd.previous);
1518     for (j = 0; j < 2; j++) free(rd.workspace[j]);
1519 
1520     eprintf1("%s" ERRPREF "Memory allocation failure from malloc().\n",
1521       epref);
1522     return_error(gs_error_VMerror);
1523   }
1524 
1525   /* Open the page and start raster mode */
1526   guard(pcl3_begin_page(out, &dev->file_data))
1527   guard(pcl3_begin_raster(out, &rd))
1528 
1529   /* Loop over scan lines */
1530   blank_lines = 0;
1531   while (eprn_get_planes((eprn_Device *)dev, (eprn_OctetString *)rd.next) == 0){
1532     /* Is this a blank (white) line? */
1533     if (dev->eprn.colour_model == eprn_DeviceRGB) {
1534       /*  White results if all three colorants use their highest intensity.
1535           Fortunately, PCL-3+ can only support two intensity levels for all
1536           colorants in an RGB palette, hence this intensity must be one for all
1537           colorants simultaneously.
1538           Because the planes returned by eprn_get_planes() are guaranteed to
1539           have no trailing zero octets, we can easily check that they are of
1540           equal length before proceeding further.
1541       */
1542       for (j = 1; j < planes && rd.next[j].length == rd.next[0].length; j++);
1543       if (j >= planes && rd.next[0].length == lengths[0]) {
1544         int k;
1545         /* All planes have the same length and cover the whole width of the
1546            page. Check that they all contain 0xFF. */
1547         j = 0;
1548         do {
1549           k = rd.next[j].length - 1;
1550           while (k > 0 && rd.next[j].str[k] == 0xFF) k--;
1551         } while (k == 0 && rd.next[j].str[0] == 0xFF && ++j < planes);
1552       }
1553     }
1554     else
1555       /* White is zero */
1556       for (j = 0; j < planes && rd.next[j].length == 0; j++);
1557 
1558     if (j == planes) blank_lines++;
1559     else {
1560       if (blank_lines > 0) {
1561         guard(pcl3_skip_groups(out, &rd, blank_lines))
1562         blank_lines = 0;
1563       }
1564       guard(pcl3_transfer_group(out, &rd))
1565     }
1566   }
1567 
1568   /* Terminate raster mode and close the page */
1569   guard(pcl3_end_raster(out, &rd))
1570   guard(pcl3_end_page(out, &dev->file_data))
1571 
1572   /* Free dynamic storage */
1573   for (j = 0; j < planes; j++) free(rd.next[j].str);
1574   if (pcl_cm_is_differential(dev->file_data.compression))
1575     for (j = 0; j < planes; j++) free(rd.previous[j].str);
1576   for (j = 0; j < 2; j++) free(rd.workspace[j]);
1577   free(lengths); free(rd.next); free(rd.previous);
1578 
1579   return 0;
1580 }
1581 
1582 #undef guard
1583