Coverage Report

Created: 2025-08-28 07:06

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