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