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