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