/src/ghostpdl/contrib/pcl3/eprn/eprnparm.c
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | File: $Id: eprnparm.c,v 1.24 2001/08/18 17:42:34 Martin Rel $ |
3 | | Contents: Device parameter handling for the ghostscript device 'eprn' |
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 | | EPRN_GS_HAS_MEDIAPOSITION |
17 | | Define this if ghostscript should in the future implement the standard |
18 | | PostScript page device parameter "MediaPosition" as a device parameter. |
19 | | Otherwise it will be stored in the eprn device. Note that |
20 | | ghostscript's input media selection algorithm *does* react to the |
21 | | parameter, and you could also specify it from PostScript. This |
22 | | implementation is only needed to make the parameter available as a |
23 | | command line option. |
24 | | |
25 | | EPRN_NO_PAGECOUNTFILE |
26 | | Define this if you do not want to use eprn's pagecount-file feature. |
27 | | You very likely must define this on Microsoft Windows. This is |
28 | | automatically defined under Visual Studio builds. |
29 | | |
30 | | EPRN_TRACE |
31 | | Define this to enable tracing. Only useful for development. |
32 | | |
33 | | ******************************************************************************/ |
34 | | |
35 | | /*****************************************************************************/ |
36 | | |
37 | | #ifndef _XOPEN_SOURCE |
38 | | #define _XOPEN_SOURCE 500 |
39 | | #endif |
40 | | |
41 | | /* Special Aladdin header, must be included before <sys/types.h> on some |
42 | | platforms (e.g., FreeBSD). */ |
43 | | #include "std.h" |
44 | | |
45 | | /* Standard headers */ |
46 | | #include <assert.h> |
47 | | #include <ctype.h> |
48 | | #include <errno.h> |
49 | | #include <stdio.h> |
50 | | #include <stdlib.h> |
51 | | #include <string.h> |
52 | | |
53 | | /* Ghostscript headers */ |
54 | | #ifdef EPRN_TRACE |
55 | | #include "gdebug.h" |
56 | | #endif /* EPRN_TRACE */ |
57 | | |
58 | | /* Special headers */ |
59 | | #include "gdeveprn.h" |
60 | | #include "gp.h" |
61 | | |
62 | | #include "gscoord.h" /* for gs_setdefaultmatrix() */ |
63 | | |
64 | | /*****************************************************************************/ |
65 | | |
66 | | #define ERRPREF "? eprn: " |
67 | | #define WARNPREF "?-W eprn: " |
68 | | |
69 | | /*****************************************************************************/ |
70 | | |
71 | | /* Data structures for string arguments to parameters */ |
72 | | |
73 | | const eprn_StringAndInt |
74 | | /* Colour models */ |
75 | | eprn_colour_model_list[] = { |
76 | | /* Values of type 'eprn_ColourModel' are assumed to be usable as indices |
77 | | into this array in order to find string representations for them. */ |
78 | | { "Gray", eprn_DeviceGray }, |
79 | | { "RGB", eprn_DeviceRGB }, |
80 | | { "CMY", eprn_DeviceCMY }, |
81 | | { "CMY+K", eprn_DeviceCMY_plus_K }, |
82 | | { "CMYK", eprn_DeviceCMYK }, |
83 | | { NULL, 0 } |
84 | | }; |
85 | | |
86 | | static const eprn_StringAndInt |
87 | | /* Intensity rendering methods */ |
88 | | intensity_rendering_list[] = { |
89 | | { "printer", eprn_IR_printer }, |
90 | | { "halftones", eprn_IR_halftones }, |
91 | | { "Floyd-Steinberg", eprn_IR_FloydSteinberg }, |
92 | | { NULL, 0} |
93 | | }; |
94 | | |
95 | | /****************************************************************************** |
96 | | |
97 | | Function: eprn_get_string |
98 | | |
99 | | This function returns a string representation of 'in_value' in '*out_value', |
100 | | based on 'table'. 'table' must be an array terminated with an entry having |
101 | | NULL as the 'name' value and must be permanently allocated and constant. |
102 | | If 'in_value' cannot be found in 'table', the function returns a non-zero |
103 | | value, otherwise zero. |
104 | | |
105 | | The string buffer in '*out_value' will be a statically allocated area which |
106 | | must not be modified. |
107 | | |
108 | | ******************************************************************************/ |
109 | | |
110 | | int eprn_get_string(int in_value, const eprn_StringAndInt *table, |
111 | | gs_param_string *out_value) |
112 | 0 | { |
113 | 0 | while (table->name != NULL && table->value != in_value) table++; |
114 | 0 | if (table->name == NULL) return -1; |
115 | | |
116 | 0 | out_value->data = (const byte *)table->name; |
117 | 0 | out_value->size = strlen(table->name); |
118 | 0 | out_value->persistent = true; |
119 | |
|
120 | 0 | return 0; |
121 | 0 | } |
122 | | |
123 | | /****************************************************************************** |
124 | | |
125 | | Function: eprn_get_int |
126 | | |
127 | | This function parses 'in_value' based on 'table' and returns the result in |
128 | | '*out_value'. 'table' must be an array, terminated with an entry having NULL |
129 | | as the value for 'name'. |
130 | | |
131 | | 'in_value' must be a string present in 'table'. If it is, the function |
132 | | returns 0, otherwise a non-zero ghostscript error value. |
133 | | |
134 | | On returning 'gs_error_VMerror', the function will have issued an error |
135 | | message. |
136 | | |
137 | | ******************************************************************************/ |
138 | | |
139 | | int eprn_get_int(const gs_param_string *in_value, |
140 | | const eprn_StringAndInt *table, int *out_value) |
141 | 0 | { |
142 | 0 | char *s; |
143 | | |
144 | | /* First we construct a properly NUL-terminated string */ |
145 | 0 | s = (char *) malloc(in_value->size + 1); |
146 | 0 | if (s == NULL) { |
147 | 0 | eprintf1(ERRPREF |
148 | 0 | "Memory allocation failure in eprn_get_int(): %s.\n", |
149 | 0 | strerror(errno)); |
150 | 0 | return_error(gs_error_VMerror); |
151 | 0 | } |
152 | 0 | strncpy(s, (const char *)in_value->data, in_value->size); |
153 | 0 | s[in_value->size] = '\0'; |
154 | | |
155 | | /* Loop over table */ |
156 | 0 | while (table->name != NULL && strcmp(table->name, s) != 0) table++; |
157 | 0 | if (table->name != NULL) *out_value = table->value; |
158 | 0 | else { |
159 | 0 | free(s); s = NULL; |
160 | 0 | return_error(gs_error_rangecheck); |
161 | 0 | } |
162 | | |
163 | 0 | free(s); s = NULL; |
164 | |
|
165 | 0 | return 0; |
166 | 0 | } |
167 | | |
168 | | /****************************************************************************** |
169 | | |
170 | | Function: eprn_dump_parameter_list |
171 | | |
172 | | This function is only used for debugging. It dumps the names of the |
173 | | parameters in the parameter list 'plist' on the debugging stream. |
174 | | |
175 | | ******************************************************************************/ |
176 | | |
177 | | #ifdef EPRN_TRACE |
178 | | |
179 | | void eprn_dump_parameter_list(gs_param_list *plist) |
180 | | { |
181 | | gs_param_enumerator_t iterator; |
182 | | gs_param_key_t key; |
183 | | int count = 0; |
184 | | |
185 | | param_init_enumerator(&iterator); |
186 | | while (param_get_next_key(plist, &iterator, &key) == 0) { |
187 | | int j; |
188 | | |
189 | | count++; |
190 | | dmlprintf(plist->memory, " `"); |
191 | | for (j = 0; j < key.size; j++) dmputc(plist->memory, key.data[j]); |
192 | | dmprintf(plist->memory, "'\n"); |
193 | | } |
194 | | dmlprintf1(plist->memory, " Number of parameters: %d.\n", count); |
195 | | |
196 | | return; |
197 | | } |
198 | | |
199 | | #endif /* EPRN_TRACE */ |
200 | | |
201 | | /****************************************************************************** |
202 | | |
203 | | Function: eprn_fillpage |
204 | | This is just a "call-through" to the default, so we can grab the gs_gstate |
205 | | |
206 | | ******************************************************************************/ |
207 | | int |
208 | | eprn_fillpage(gx_device *dev, gs_gstate * pgs, gx_device_color *pdevc) |
209 | 0 | { |
210 | 0 | eprn_Eprn *eprn = &((eprn_Device *)dev)->eprn; |
211 | |
|
212 | 0 | eprn->pgs = pgs; |
213 | |
|
214 | 0 | return (*eprn->orig_fillpage)(dev, pgs, pdevc); |
215 | 0 | } |
216 | | |
217 | | |
218 | | static void eprn_replace_fillpage(gx_device *dev) |
219 | 0 | { |
220 | 0 | eprn_Eprn *eprn = &((eprn_Device *)dev)->eprn; |
221 | |
|
222 | 0 | if (dev->procs.fillpage != eprn_fillpage) { |
223 | 0 | eprn->orig_fillpage = dev->procs.fillpage; |
224 | 0 | dev->procs.fillpage = eprn_fillpage; |
225 | 0 | } |
226 | 0 | } |
227 | | |
228 | | |
229 | | /****************************************************************************** |
230 | | |
231 | | Function: eprn_get_params |
232 | | |
233 | | This function returns to the caller information about the values of |
234 | | parameters defined for the device in the 'eprn' part and its base devices. |
235 | | |
236 | | The function returns zero on success and a negative value on error. |
237 | | |
238 | | ******************************************************************************/ |
239 | | |
240 | | int eprn_get_params(gx_device *device, gs_param_list *plist) |
241 | 0 | { |
242 | 0 | gs_param_string string_value; |
243 | 0 | const eprn_Eprn *eprn = &((eprn_Device *)device)->eprn; |
244 | 0 | int rc; |
245 | |
|
246 | | #ifdef EPRN_TRACE |
247 | | if_debug0(EPRN_TRACE_CHAR, "! eprn_get_params()...\n"); |
248 | | #endif |
249 | |
|
250 | 0 | eprn_replace_fillpage(device); |
251 | | |
252 | | /* Base class parameters */ |
253 | 0 | rc = gdev_prn_get_params(device, plist); |
254 | 0 | if (rc < 0) return rc; |
255 | | |
256 | | /* Number of intensity levels. The casts are used to get rid of compiler |
257 | | warnings because the *_levels are unsigned. */ |
258 | 0 | if ((rc = param_write_int(plist, "BlackLevels", |
259 | 0 | (const int *)&eprn->black_levels)) < 0) return rc; |
260 | 0 | if ((rc = param_write_int(plist, "CMYLevels", |
261 | 0 | (const int *)&eprn->non_black_levels)) < 0) return rc; |
262 | 0 | if ((rc = param_write_int(plist, "RGBLevels", |
263 | 0 | (const int *)&eprn->non_black_levels)) < 0) return rc; |
264 | | |
265 | | /* Colour model */ |
266 | 0 | eprn_get_string(eprn->colour_model, eprn_colour_model_list, &string_value); |
267 | 0 | if ((rc = param_write_string(plist, "ColourModel", &string_value)) < 0 || |
268 | 0 | (rc = param_write_string(plist, "ColorModel", &string_value)) < 0) |
269 | 0 | return rc; |
270 | | |
271 | | /* CUPS page accounting */ |
272 | 0 | if ((rc = param_write_bool(plist, "CUPSAccounting", &eprn->CUPS_accounting)) |
273 | 0 | < 0) return rc; |
274 | | |
275 | | /* CUPS message format */ |
276 | 0 | if ((rc = param_write_bool(plist, "CUPSMessages", &eprn->CUPS_messages)) < 0) |
277 | 0 | return rc; |
278 | | |
279 | | /* Intensity rendering */ |
280 | 0 | eprn_get_string(eprn->intensity_rendering, intensity_rendering_list, |
281 | 0 | &string_value); |
282 | 0 | if ((rc = param_write_string(plist, "IntensityRendering", &string_value)) < 0) |
283 | 0 | return rc; |
284 | | |
285 | | /* Leading edge */ |
286 | 0 | if (eprn->leading_edge_set) { |
287 | 0 | if ((rc = param_write_int(plist, "LeadingEdge", &eprn->default_orientation)) |
288 | 0 | < 0) return rc; |
289 | 0 | } |
290 | 0 | else |
291 | 0 | if ((rc = param_write_null(plist, "LeadingEdge")) < 0) return rc; |
292 | | |
293 | | /* Media configuration file */ |
294 | 0 | if (eprn->media_file == NULL) { |
295 | 0 | if ((rc = param_write_null(plist, "MediaConfigurationFile")) < 0) |
296 | 0 | return rc; |
297 | 0 | } |
298 | 0 | else { |
299 | 0 | string_value.data = (const byte *)eprn->media_file; |
300 | 0 | string_value.size = strlen((const char *)string_value.data); |
301 | 0 | string_value.persistent = false; |
302 | 0 | if ((rc = |
303 | 0 | param_write_string(plist, "MediaConfigurationFile", &string_value)) < 0) |
304 | 0 | return rc; |
305 | 0 | } |
306 | | |
307 | 0 | #ifndef EPRN_GS_HAS_MEDIAPOSITION |
308 | | /* Requested input media position */ |
309 | 0 | if (eprn->media_position_set) { |
310 | 0 | if ((rc = param_write_int(plist, "MediaPosition", &eprn->media_position)) |
311 | 0 | < 0) return rc; |
312 | 0 | } |
313 | 0 | else |
314 | 0 | if ((rc = param_write_null(plist, "MediaPosition")) < 0) return rc; |
315 | 0 | #endif /* EPRN_GS_HAS_MEDIAPOSITION */ |
316 | | |
317 | 0 | #ifndef EPRN_NO_PAGECOUNTFILE |
318 | | /* Page count file */ |
319 | 0 | if (eprn->pagecount_file == NULL) { |
320 | 0 | if ((rc = param_write_null(plist, "PageCountFile")) < 0) return rc; |
321 | 0 | } |
322 | 0 | else { |
323 | 0 | string_value.data = (const byte *)eprn->pagecount_file; |
324 | 0 | string_value.size = strlen((const char *)string_value.data); |
325 | 0 | string_value.persistent = false; |
326 | 0 | if ((rc = param_write_string(plist, "PageCountFile", &string_value)) < 0) |
327 | 0 | return rc; |
328 | 0 | } |
329 | 0 | #endif /* EPRN_NO_PAGECOUNTFILE */ |
330 | | |
331 | 0 | return 0; |
332 | 0 | } |
333 | | |
334 | | /****************************************************************************** |
335 | | |
336 | | Function: is_word |
337 | | |
338 | | This function returns a non-zero value iff the string beginning at 's' is |
339 | | identical with the string pointed to by 'word' and is followed either by a |
340 | | blank character or '\0'. |
341 | | |
342 | | ******************************************************************************/ |
343 | | |
344 | | static int is_word(const char *s, const char *word) |
345 | 0 | { |
346 | 0 | size_t l = strlen(word); |
347 | 0 | if (strncmp(s, word, l) != 0) return 0; |
348 | 0 | return s[l] == '\0' || isspace(s[l]); |
349 | 0 | } |
350 | | |
351 | | /****************************************************************************** |
352 | | |
353 | | Function: next_word |
354 | | |
355 | | This function returns a pointer to the beginning of the next blank-separated |
356 | | word in the string pointed to by 's'. If s[0] is not blank, the character is |
357 | | considered to be part of the current word, i.e. the word to be returned is |
358 | | the one following. |
359 | | |
360 | | If there is no next word in this sense, the function returns NULL. |
361 | | |
362 | | ******************************************************************************/ |
363 | | |
364 | | static char *next_word(char *s) |
365 | 0 | { |
366 | | /* Skip current word */ |
367 | 0 | while (*s != '\0' && !isspace(*s)) s++; |
368 | | |
369 | | /* Skip intermediate blanks */ |
370 | 0 | while (*s != '\0' && isspace(*s)) s++; |
371 | |
|
372 | 0 | return *s == '\0'? NULL: s; |
373 | 0 | } |
374 | | |
375 | | /****************************************************************************** |
376 | | |
377 | | Function: eprn_read_media_data |
378 | | |
379 | | This function reads a media configuration file and stores the result in |
380 | | '*eprn'. The file name must already have been stored in 'eprn->media_file', |
381 | | 'eprn->media_overrides' should be NULL. |
382 | | |
383 | | The function returns zero on success and a non-zero ghostscript error value |
384 | | otherwise. In the latter case, an error message will have been issued. |
385 | | |
386 | | ******************************************************************************/ |
387 | | |
388 | 0 | #define BUFFER_SIZE 200 |
389 | | /* should be large enough for a single line */ |
390 | | |
391 | 0 | #define cleanup() (free(list), gp_fclose(f)) |
392 | | |
393 | | static int eprn_read_media_data(mediasize_table *tables, eprn_Eprn *eprn, gs_memory_t *memory) |
394 | 0 | { |
395 | 0 | char buffer[BUFFER_SIZE]; |
396 | 0 | const char |
397 | 0 | *epref = eprn->CUPS_messages? CUPS_ERRPREF: "", |
398 | 0 | *wpref = eprn->CUPS_messages? CUPS_WARNPREF: ""; |
399 | 0 | gp_file *f; |
400 | 0 | float conversion_factor = BP_PER_IN; |
401 | | /* values read have to be multiplied by this value to obtain bp */ |
402 | 0 | int |
403 | 0 | line = 0, /* line number */ |
404 | 0 | read = 0; /* number of entries read so far */ |
405 | 0 | eprn_PageDescription *list = NULL; |
406 | | |
407 | | /* Open the file */ |
408 | 0 | if ((f = gp_fopen(memory, eprn->media_file, "r")) == NULL) { |
409 | 0 | eprintf5("%s" ERRPREF "Error opening the media configuration file\n" |
410 | 0 | "%s `%s'\n%s for reading: %s.\n", |
411 | 0 | epref, epref, eprn->media_file, epref, strerror(errno)); |
412 | 0 | return_error(gs_error_invalidfileaccess); |
413 | 0 | } |
414 | | |
415 | | /* Loop over input lines */ |
416 | 0 | while (gp_fgets(buffer, BUFFER_SIZE, f) != NULL) { |
417 | 0 | char *s, *t; |
418 | 0 | eprn_PageDescription *current; |
419 | 0 | int chars_read; |
420 | |
|
421 | 0 | line++; |
422 | | |
423 | | /* Check for buffer overflow */ |
424 | 0 | if ((s = strchr(buffer, '\n')) == NULL && gp_fgetc(f) != EOF) { |
425 | 0 | eprintf5("%s" ERRPREF "Exceeding line length %d in " |
426 | 0 | "media configuration file\n%s %s, line %d.\n", |
427 | 0 | epref, BUFFER_SIZE - 2 /* '\n'+'\0' */, epref, eprn->media_file, line); |
428 | 0 | cleanup(); |
429 | 0 | return_error(gs_error_limitcheck); |
430 | 0 | } |
431 | | |
432 | | /* Eliminate the newline character */ |
433 | 0 | if (s != NULL) *s = '\0'; |
434 | | |
435 | | /* Originally, I did nothing further at this point and used a |
436 | | "%g %g %g %g %n" format in the sscanf() call below to skip trailing |
437 | | blanks. This does not work with Microsoft Visual C up to at least |
438 | | version 6 (_MSC_VER is 1200) because the variable for %n will never be |
439 | | set. If one drops the blank, it will be set, also if there are |
440 | | additional directives after %n. In addition, Cygwin does not (as of |
441 | | early 2001) set the %n variable if there is trailing white space in the |
442 | | string scanned. I don't want to know what's going on there, I just |
443 | | foil these bugs by removing all trailing white space from the input |
444 | | line which means I don't have to scan it afterwards. |
445 | | */ |
446 | 0 | if (s == NULL) s = strchr(buffer, '\0'); |
447 | 0 | while (buffer < s && isspace(*(s-1))) s--; |
448 | 0 | *s = '\0'; |
449 | | |
450 | | /* Ignore blank and comment lines */ |
451 | 0 | s = buffer; |
452 | 0 | while (isspace(*s)) s++; |
453 | 0 | if (*s == '\0' || *s == '#') continue; |
454 | | |
455 | | /* Check for unit specification */ |
456 | 0 | if (is_word(s, "unit")) { |
457 | 0 | char *unit_name = next_word(s); |
458 | 0 | if (unit_name != NULL) { |
459 | 0 | s = next_word(unit_name); |
460 | 0 | if (s == NULL) { |
461 | 0 | if (is_word(unit_name, "in")) { |
462 | 0 | conversion_factor = BP_PER_IN; |
463 | 0 | continue; |
464 | 0 | } |
465 | 0 | if (is_word(unit_name, "mm")) { |
466 | 0 | conversion_factor = BP_PER_MM; |
467 | 0 | continue; |
468 | 0 | } |
469 | 0 | } |
470 | | /* If 's' is not NULL or the unit is not recognized, the error message |
471 | | will be generated when the attempt to read the whole line as a media |
472 | | specification will fail because there is no media size called |
473 | | "unit". */ |
474 | 0 | } |
475 | 0 | } |
476 | | |
477 | | /* Extend the list */ |
478 | 0 | { |
479 | 0 | eprn_PageDescription *new_list; |
480 | 0 | new_list = (eprn_PageDescription *) |
481 | 0 | realloc(list, (read+1)*sizeof(eprn_PageDescription)); |
482 | 0 | if (new_list == NULL) { |
483 | 0 | eprintf2("%s" ERRPREF |
484 | 0 | "Memory allocation failure in eprn_read_media_data(): %s.\n", |
485 | 0 | epref, strerror(errno)); |
486 | 0 | cleanup(); |
487 | 0 | return_error(gs_error_VMerror); |
488 | 0 | } |
489 | 0 | list = new_list; |
490 | 0 | } |
491 | | |
492 | | /* Set 'current' on the new entry */ |
493 | 0 | current = list + read; |
494 | | |
495 | | /* Isolate and identify the media size name */ |
496 | 0 | s = buffer; |
497 | 0 | while (isspace(*s)) s++; |
498 | 0 | t = s + 1; /* we checked above that the line is not empty */ |
499 | 0 | while (*t != '\0' && !isspace(*t)) t++; |
500 | 0 | if (*t != '\0') { |
501 | 0 | *t = '\0'; |
502 | 0 | t++; |
503 | 0 | } |
504 | 0 | { |
505 | 0 | ms_MediaCode code = ms_find_code_from_name(tables, s, eprn->flag_desc); |
506 | 0 | if (code == ms_none) { |
507 | 0 | eprintf5("%s" ERRPREF "Unknown media name (%s) in " |
508 | 0 | "media configuration file\n%s %s, line %d.\n", |
509 | 0 | epref, s, epref, eprn->media_file, line); |
510 | 0 | cleanup(); |
511 | 0 | return_error(gs_error_rangecheck); |
512 | 0 | } |
513 | 0 | if (code & MS_ROTATED_FLAG) { |
514 | 0 | eprintf5("%s" ERRPREF "Invalid substring \"" MS_ROTATED_STRING |
515 | 0 | "\" in media name (%s)\n" |
516 | 0 | "%s in media configuration file %s, line %d.\n", |
517 | 0 | epref, s, epref, eprn->media_file, line); |
518 | 0 | cleanup(); |
519 | 0 | return_error(gs_error_rangecheck); |
520 | 0 | } |
521 | 0 | current->code = code; |
522 | 0 | } |
523 | | |
524 | | /* Look for margins */ |
525 | 0 | if (sscanf(t, "%g %g %g %g%n", ¤t->left, |
526 | 0 | ¤t->bottom, ¤t->right, ¤t->top, &chars_read) != 4 || |
527 | 0 | t[chars_read] != '\0') { |
528 | 0 | if (*t != '\0') *(t-1) = ' '; /* remove NUL after media name */ |
529 | 0 | eprintf5("%s" ERRPREF |
530 | 0 | "Syntax error in media configuration file %s, line %d:\n%s %s\n", |
531 | 0 | epref, eprn->media_file, line, epref, buffer); |
532 | 0 | cleanup(); |
533 | 0 | return_error(gs_error_rangecheck); |
534 | 0 | } |
535 | | |
536 | | /* Check for sign */ |
537 | 0 | if (current->left < 0 || current->bottom < 0 || current->right < 0 || |
538 | 0 | current->top < 0) { |
539 | 0 | eprintf4("%s" ERRPREF |
540 | 0 | "Ghostscript does not support negative margins (line %d in the\n" |
541 | 0 | "%s media configuration file %s).\n", |
542 | 0 | epref, line, epref, eprn->media_file); |
543 | 0 | cleanup(); |
544 | 0 | return_error(gs_error_rangecheck); |
545 | 0 | } |
546 | | |
547 | 0 | read++; |
548 | | |
549 | | /* Convert to bp */ |
550 | 0 | current->left *= conversion_factor; |
551 | 0 | current->bottom *= conversion_factor; |
552 | 0 | current->right *= conversion_factor; |
553 | 0 | current->top *= conversion_factor; |
554 | | |
555 | | /* A margin for custom page sizes without the corresponding capability in |
556 | | the printer is useless although it would not lead to a failure of eprn. |
557 | | The user might not notice the reason without help, hence we check. */ |
558 | 0 | if (ms_without_flags(current->code) == ms_CustomPageSize && |
559 | 0 | eprn->cap->custom == NULL) |
560 | 0 | eprintf6("%s" WARNPREF "The media configuration file %s\n" |
561 | 0 | "%s contains a custom page size entry in line %d, " |
562 | 0 | "but custom page sizes\n" |
563 | 0 | "%s are not supported by the %s.\n", |
564 | 0 | wpref, eprn->media_file, wpref, line, wpref, eprn->cap->name); |
565 | 0 | } |
566 | 0 | if (gp_ferror(f)) { |
567 | 0 | eprintf2("%s" ERRPREF |
568 | 0 | "Unidentified system error while reading `%s'.\n", |
569 | 0 | epref, eprn->media_file); |
570 | 0 | cleanup(); |
571 | 0 | return_error(gs_error_invalidfileaccess); |
572 | 0 | } |
573 | 0 | gp_fclose(f); |
574 | | |
575 | | /* Was the file empty? */ |
576 | 0 | if (read == 0) { |
577 | 0 | eprintf3("%s" ERRPREF "The media configuration file %s\n" |
578 | 0 | "%s does not contain any media information.\n", |
579 | 0 | epref, eprn->media_file, epref); |
580 | 0 | return_error(gs_error_rangecheck); |
581 | 0 | } |
582 | | |
583 | | /* Create a list in the device structure */ |
584 | 0 | eprn->media_overrides = (eprn_PageDescription *) gs_malloc(memory, read + 1, |
585 | 0 | sizeof(eprn_PageDescription), "eprn_read_media_data"); |
586 | 0 | if (eprn->media_overrides == NULL) { |
587 | 0 | eprintf1("%s" ERRPREF |
588 | 0 | "Memory allocation failure from gs_malloc() in eprn_read_media_data().\n", |
589 | 0 | epref); |
590 | 0 | free(list); |
591 | 0 | return_error(gs_error_VMerror); |
592 | 0 | } |
593 | | |
594 | | /* Copy the list and set the sentinel entry */ |
595 | 0 | memcpy(eprn->media_overrides, list, read*sizeof(eprn_PageDescription)); |
596 | 0 | eprn->media_overrides[read].code = ms_none; |
597 | | |
598 | | /* Cleanup */ |
599 | 0 | free(list); |
600 | |
|
601 | 0 | return 0; |
602 | 0 | } |
603 | | |
604 | | #undef BUFFER_SIZE |
605 | | #undef cleanup |
606 | | |
607 | | /****************************************************************************** |
608 | | |
609 | | Function: eprn_set_media_data |
610 | | |
611 | | This function sets the media size and margin information in an 'eprn' device |
612 | | from the specified media configuration file. |
613 | | |
614 | | The return code will be zero an success and a ghostscript error code |
615 | | otherwise. In the latter case, an error message will have been issued. |
616 | | |
617 | | The 'length' may be positive in which case it denotes the length of the |
618 | | string 'media_file' or zero in which case the string is assumed to be |
619 | | NUL-terminated. |
620 | | |
621 | | A NULL value or an empty string for 'media_file' is permitted and removes |
622 | | all previous media descriptions read from a media configuration file. |
623 | | |
624 | | ******************************************************************************/ |
625 | | |
626 | | int eprn_set_media_data(eprn_Device *dev, const char *media_file, size_t length) |
627 | 0 | { |
628 | 0 | eprn_Eprn *eprn = &dev->eprn; |
629 | 0 | const char *epref = eprn->CUPS_messages? CUPS_ERRPREF: ""; |
630 | 0 | int rc = 0; |
631 | | |
632 | | /* Any previous size determination is obsolete now */ |
633 | 0 | eprn->code = ms_none; |
634 | | |
635 | | /* Free old storage */ |
636 | 0 | if (eprn->media_file != NULL) { |
637 | 0 | gs_free(dev->memory->non_gc_memory, eprn->media_file, strlen(eprn->media_file) + 1, |
638 | 0 | sizeof(char), "eprn_set_media_data"); |
639 | 0 | eprn->media_file = NULL; |
640 | 0 | } |
641 | 0 | if (eprn->media_overrides != NULL) { |
642 | 0 | int n = 0; |
643 | 0 | while (eprn->media_overrides[n].code != ms_none) n++; |
644 | 0 | gs_free(dev->memory->non_gc_memory, eprn->media_overrides, n+1, sizeof(eprn_PageDescription), |
645 | 0 | "eprn_set_media_data"); |
646 | 0 | eprn->media_overrides = NULL; |
647 | 0 | } |
648 | | |
649 | | /* Set the file name length if not given */ |
650 | 0 | if (media_file != NULL && length == 0) length = strlen(media_file); |
651 | | |
652 | | /* Read media configuration file, unless the name is NULL or the empty |
653 | | string */ |
654 | 0 | if (media_file != NULL && length > 0) { |
655 | 0 | eprn->media_file = (char *)gs_malloc(dev->memory->non_gc_memory, length + 1, sizeof(char), |
656 | 0 | "eprn_set_media_data"); |
657 | 0 | if (eprn->media_file == NULL) { |
658 | 0 | eprintf1("%s" ERRPREF |
659 | 0 | "Memory allocation failure from gs_malloc() in " |
660 | 0 | "eprn_set_media_data().\n", |
661 | 0 | epref); |
662 | 0 | rc = gs_error_VMerror; |
663 | 0 | } |
664 | 0 | else { |
665 | 0 | strncpy(eprn->media_file, media_file, length); |
666 | 0 | eprn->media_file[length] = '\0'; |
667 | 0 | if ((rc = eprn_read_media_data(&dev->eprn.table, eprn, dev->memory->non_gc_memory)) != 0) { |
668 | 0 | gs_free(dev->memory->non_gc_memory, eprn->media_file, length + 1, sizeof(char), |
669 | 0 | "eprn_set_media_data"); |
670 | 0 | eprn->media_file = NULL; |
671 | 0 | } |
672 | 0 | } |
673 | 0 | } |
674 | |
|
675 | 0 | return rc; |
676 | 0 | } |
677 | | |
678 | | /****************************************************************************** |
679 | | |
680 | | Function: eprn_bits_for_levels |
681 | | |
682 | | This function returns the number of bits used to represent 'levels' intensity |
683 | | levels. 'levels' must be <= (ULONG_MAX+1)/2. |
684 | | |
685 | | ******************************************************************************/ |
686 | | |
687 | | unsigned int eprn_bits_for_levels(unsigned int levels) |
688 | 0 | { |
689 | 0 | unsigned int bits = 0; |
690 | 0 | unsigned long n; |
691 | |
|
692 | 0 | for (n = 1; n < levels; n *= 2) bits++; |
693 | |
|
694 | 0 | return bits; |
695 | 0 | } |
696 | | |
697 | | /****************************************************************************** |
698 | | |
699 | | Function: res_supported |
700 | | |
701 | | 'list' must either bei NULL (all resolutions are accepted) or point to a |
702 | | list of resolutions terminated with a {0.0, 0.0} entry. |
703 | | |
704 | | ******************************************************************************/ |
705 | | |
706 | | static bool res_supported(const eprn_Resolution *list, float hres, float vres) |
707 | 0 | { |
708 | 0 | if (list == NULL) return true; |
709 | | |
710 | 0 | while (list->h > 0.0 && (list->h != hres || list->v != vres)) list++; |
711 | |
|
712 | 0 | return list->h > 0.0; |
713 | 0 | } |
714 | | |
715 | | /****************************************************************************** |
716 | | |
717 | | Function: levels_supported |
718 | | |
719 | | 'list' may not be NULL and must point to a {0,0}-terminated list of |
720 | | supported ranges. |
721 | | |
722 | | ******************************************************************************/ |
723 | | |
724 | | static bool levels_supported(const eprn_IntensityLevels *list, |
725 | | unsigned int levels) |
726 | 0 | { |
727 | 0 | while (list->from > 0 && (levels < list->from || list->to < levels)) list++; |
728 | |
|
729 | 0 | return list->from > 0; |
730 | 0 | } |
731 | | |
732 | | /****************************************************************************** |
733 | | |
734 | | Function: reslev_supported |
735 | | |
736 | | ******************************************************************************/ |
737 | | |
738 | | static int reslev_supported(const eprn_ResLev *entry, float hres, float vres, |
739 | | unsigned int levels) |
740 | 0 | { |
741 | 0 | return res_supported(entry->resolutions, hres, vres) && |
742 | 0 | levels_supported(entry->levels, levels); |
743 | 0 | } |
744 | | |
745 | | /****************************************************************************** |
746 | | |
747 | | Function: eprn_check_colour_info |
748 | | |
749 | | This function checks the arguments starting at 'model' whether they are |
750 | | supported according to 'list'. This list must satisfy the constraints for |
751 | | 'colour_info' in 'eprn_PrinterDescription'. |
752 | | |
753 | | The function returns zero if the values are supported and a non-zero value |
754 | | if they are not. |
755 | | |
756 | | ******************************************************************************/ |
757 | | |
758 | | int eprn_check_colour_info(const eprn_ColourInfo *list, |
759 | | eprn_ColourModel *model, float *hres, float *vres, |
760 | | unsigned int *black_levels, unsigned int *non_black_levels) |
761 | 0 | { |
762 | 0 | const eprn_ColourInfo *entry; |
763 | | |
764 | | /* Search for a match. Successful exits are in the middle of the loop. */ |
765 | 0 | for (entry = list; entry->info[0] != NULL; entry++) |
766 | 0 | if (entry->colour_model == *model || |
767 | 0 | (entry->colour_model == eprn_DeviceCMYK && |
768 | 0 | *model == eprn_DeviceCMY_plus_K)) { |
769 | 0 | const eprn_ResLev *rl; |
770 | 0 | unsigned int levels = (entry->colour_model == eprn_DeviceRGB || |
771 | 0 | entry->colour_model == eprn_DeviceCMY? *non_black_levels: |
772 | 0 | *black_levels); |
773 | |
|
774 | 0 | for (rl = entry->info[0]; rl->levels != NULL; rl++) |
775 | 0 | if (reslev_supported(rl, *hres, *vres, levels)) { |
776 | 0 | const eprn_ResLev *rl2 = NULL; |
777 | | |
778 | | /* Check on info[1] needed? */ |
779 | 0 | if (entry->colour_model == eprn_DeviceGray || |
780 | 0 | entry->colour_model == eprn_DeviceRGB || |
781 | 0 | entry->colour_model == eprn_DeviceCMY) |
782 | 0 | return 0; |
783 | | |
784 | | /* CMY+K or CMYK process colour models */ |
785 | 0 | if (entry->info[1] != NULL) { |
786 | 0 | for (rl2 = entry->info[1]; rl2->levels != NULL; rl2++) |
787 | 0 | if (reslev_supported(rl2, *hres, *vres, *non_black_levels)) break; |
788 | 0 | } |
789 | 0 | if ((entry->info[1] == NULL && *black_levels == *non_black_levels) || |
790 | 0 | (entry->info[1] != NULL && rl2->levels != NULL)) |
791 | 0 | return 0; |
792 | 0 | } |
793 | 0 | } |
794 | | |
795 | 0 | return -1; |
796 | 0 | } |
797 | | |
798 | | /****************************************************************************** |
799 | | |
800 | | Function: set_derived_colour_data |
801 | | |
802 | | This routine determines and sets various derived values in the device |
803 | | structure based on the number of black and non-black levels requested. |
804 | | |
805 | | The values to be set are 'eprn.bits_per_colorant' and the fields 'depth', |
806 | | 'max_gray', 'max_color', 'dither_grays' and 'dither_colors' in the |
807 | | 'color_info' structure. |
808 | | |
809 | | The parameters 'black_levels' and 'non_black_levels' must be in the range |
810 | | 0 to 256 without 1. At least one of the two must be positive. |
811 | | |
812 | | ******************************************************************************/ |
813 | | |
814 | | static void set_derived_colour_data(eprn_Device *dev) |
815 | 0 | { |
816 | 0 | eprn_Eprn *eprn = &dev->eprn; |
817 | 0 | unsigned int levels; |
818 | | |
819 | | /* Choose equal number of bits in 'gx_color_index' for all components present |
820 | | */ |
821 | 0 | if (eprn->intensity_rendering == eprn_IR_FloydSteinberg) levels = 256; |
822 | 0 | else if (eprn->black_levels >= eprn->non_black_levels) |
823 | 0 | levels = eprn->black_levels; |
824 | 0 | else levels = eprn->non_black_levels; |
825 | 0 | eprn->bits_per_colorant = eprn_bits_for_levels(levels); |
826 | | |
827 | | /* For the depth, consider all components and adjust to possible values. |
828 | | Ghostscript permits pixel depths 1, 2, 4, 8, 16, 24 and 32. */ |
829 | 0 | dev->color_info.depth = |
830 | 0 | (eprn->non_black_levels == 0? 1: 4) * eprn->bits_per_colorant; |
831 | | /* No distinction between non-Gray colour models */ |
832 | 0 | if (dev->color_info.depth > 2) { |
833 | 0 | if (dev->color_info.depth <= 4) dev->color_info.depth = 4; |
834 | 0 | else if (dev->color_info.depth <= 8) dev->color_info.depth = 8; |
835 | 0 | else dev->color_info.depth = ((dev->color_info.depth + 7)/8)*8; |
836 | | /* Next multiple of 8 */ |
837 | 0 | } |
838 | | |
839 | | /* Set ghostscript's color_info data. This is an area where ghostscript's |
840 | | documentation (Drivers.htm) is not particularly intelligible. For |
841 | | example: can there be situations where the dither_* parameters are |
842 | | different from their corresponding max_* parameter plus one? |
843 | | */ |
844 | 0 | if (eprn->intensity_rendering != eprn_IR_halftones) { |
845 | | /* Here we cover two cases: retaining as much colour information as |
846 | | possible and effectively setting up 1-pixel halftone cells. Both |
847 | | demand that ghostscript is prevented from doing halftoning; the |
848 | | remaining difference (which is the essential part) is then handled in |
849 | | our colour mapping functions. |
850 | | According to Drivers.htm, a value of at least 31 for max_gray or |
851 | | max_color (actually, the documentation says "max_rgb") leads to |
852 | | ghostscript using the colour returned by the device if valid |
853 | | instead of using the dither parameters for halftoning. The actual |
854 | | values for the max_* parameters should then be irrelevant. |
855 | | */ |
856 | 0 | if (eprn->non_black_levels > 0) dev->color_info.max_color = 255; |
857 | 0 | else dev->color_info.max_color = 0; |
858 | 0 | dev->color_info.max_gray = 255; |
859 | | |
860 | | /* As long as our colour mapping functions return valid color indices, the |
861 | | following parameters should be irrelevant. */ |
862 | 0 | dev->color_info.dither_grays = 256; |
863 | 0 | if (dev->color_info.num_components == 1) dev->color_info.dither_colors = 0; |
864 | 0 | else dev->color_info.dither_colors = dev->color_info.max_color + 1; |
865 | 0 | } |
866 | 0 | else { |
867 | | /* Let ghostscript do halftoning */ |
868 | 0 | if (eprn->non_black_levels > 0) |
869 | 0 | dev->color_info.max_color = eprn->non_black_levels - 1; |
870 | 0 | else dev->color_info.max_color = 0; |
871 | 0 | if (eprn->black_levels > 0) |
872 | 0 | dev->color_info.max_gray = eprn->black_levels - 1; |
873 | 0 | else dev->color_info.max_gray = dev->color_info.max_color; |
874 | | |
875 | | /* The dither parameters */ |
876 | 0 | if (eprn->black_levels > 0) |
877 | 0 | dev->color_info.dither_grays = eprn->black_levels; |
878 | 0 | else dev->color_info.dither_grays = eprn->non_black_levels; |
879 | 0 | if (eprn->non_black_levels > 0) |
880 | 0 | dev->color_info.dither_colors = eprn->non_black_levels; |
881 | 0 | else dev->color_info.dither_colors = 0; |
882 | 0 | } |
883 | |
|
884 | 0 | return; |
885 | 0 | } |
886 | | |
887 | | /****************************************************************************** |
888 | | |
889 | | Function: eprn_put_params |
890 | | |
891 | | This function reads a parameter list, extracts the parameters known to the |
892 | | 'eprn' device, and configures the device appropriately. This includes |
893 | | parameters defined by base devices. |
894 | | |
895 | | If an error occurs in the processing of parameters, the function will |
896 | | return a negative value, otherwise zero. |
897 | | |
898 | | This function does *not* exhibit transactional behaviour as requested in |
899 | | gsparam.h, i.e. on error the parameter values in the device structure |
900 | | might have changed. However, all values will be individually valid. |
901 | | |
902 | | For most of the parameters an attempt to set them closes the device if it is |
903 | | open. |
904 | | |
905 | | ******************************************************************************/ |
906 | | |
907 | | int eprn_put_params(gx_device *dev, gs_param_list *plist) |
908 | 0 | { |
909 | 0 | bool colour_mode_given_and_valid = false; |
910 | 0 | gs_param_name pname; |
911 | 0 | gs_param_string string_value; |
912 | 0 | eprn_Eprn *eprn = &((eprn_Device *)dev)->eprn; |
913 | 0 | const char |
914 | 0 | *epref = eprn->CUPS_messages? CUPS_ERRPREF: "", |
915 | 0 | *wpref = eprn->CUPS_messages? CUPS_WARNPREF: ""; |
916 | 0 | float mediasize[2]; |
917 | 0 | int |
918 | 0 | height = dev->height, |
919 | 0 | last_error = 0, |
920 | 0 | temp, |
921 | 0 | rc, |
922 | 0 | width = dev->width; |
923 | |
|
924 | | #ifdef EPRN_TRACE |
925 | | if (gs_debug_c(EPRN_TRACE_CHAR)) { |
926 | | dmlprintf(dev->memory, |
927 | | "! eprn_put_params() called with the following device parameters:\n"); |
928 | | eprn_dump_parameter_list(plist); |
929 | | } |
930 | | #endif /* EPRN_TRACE */ |
931 | |
|
932 | 0 | eprn_replace_fillpage(dev); |
933 | | |
934 | | /* Remember initial page size */ |
935 | 0 | for (temp = 0; temp < 2; temp++) mediasize[temp] = dev->MediaSize[temp]; |
936 | | |
937 | | /* CUPS message format. This should be the first parameter to be set which is |
938 | | a problem because it should happen even before the put_params methods of |
939 | | derived devices are called. However, note that in a CUPS filter |
940 | | "CUPSMessages" will usually be set from the command line while most |
941 | | remaining parameters will be set via setpagedevice. Hence this will come |
942 | | first anyway except for problems for which the print administrator is |
943 | | responsible, not the ordinary user. */ |
944 | 0 | if ((rc = param_read_bool(plist, "CUPSMessages", &eprn->CUPS_messages)) == 0) |
945 | 0 | { |
946 | 0 | epref = eprn->CUPS_messages? CUPS_ERRPREF: ""; |
947 | 0 | wpref = eprn->CUPS_messages? CUPS_WARNPREF: ""; |
948 | 0 | } |
949 | 0 | else if (rc < 0) last_error = rc; |
950 | | |
951 | | /* Read colour model into 'temp'. For those colonials across the pond we also |
952 | | accept the barbarized spelling variant. |
953 | | */ |
954 | 0 | #define colour_model(option) \ |
955 | 0 | if ((rc = param_read_string(plist, (pname = option), &string_value)) == 0) { \ |
956 | 0 | rc = eprn_get_int(&string_value, eprn_colour_model_list, &temp); \ |
957 | 0 | if (rc != 0) { \ |
958 | 0 | if (rc != gs_error_VMerror) { \ |
959 | 0 | eprintf1("%s" ERRPREF "Unknown colour model: `", epref); \ |
960 | 0 | errwrite(dev->memory, (const char *)string_value.data, sizeof(char)*string_value.size); \ |
961 | 0 | eprintf("'.\n"); \ |
962 | 0 | } \ |
963 | 0 | last_error = rc; \ |
964 | 0 | param_signal_error(plist, pname, last_error); \ |
965 | 0 | } \ |
966 | 0 | else colour_mode_given_and_valid = true; \ |
967 | 0 | } \ |
968 | 0 | else if (rc < 0) last_error = rc; |
969 | |
|
970 | 0 | colour_model("ColorModel") |
971 | 0 | colour_model("ColourModel") /* overrides if both are given */ |
972 | |
|
973 | 0 | #undef colour_model |
974 | |
|
975 | 0 | if (colour_mode_given_and_valid) { |
976 | 0 | if (eprn->colour_model != temp && dev->is_open) gs_closedevice(dev); |
977 | | /* The close_device method can fail, but what should I do then? */ |
978 | 0 | eprn->colour_model = temp; |
979 | | |
980 | | /* Set the native colour space */ |
981 | 0 | switch(eprn->colour_model) { |
982 | 0 | case eprn_DeviceGray: |
983 | 0 | dev->color_info.num_components = 1; break; |
984 | 0 | case eprn_DeviceRGB: |
985 | | /*FALLTHROUGH*/ |
986 | 0 | case eprn_DeviceCMY: |
987 | | /*FALLTHROUGH*/ |
988 | 0 | case eprn_DeviceCMY_plus_K: |
989 | 0 | dev->color_info.num_components = 3; break; |
990 | 0 | case eprn_DeviceCMYK: |
991 | 0 | dev->color_info.num_components = 4; break; |
992 | 0 | default: |
993 | 0 | assert(0); |
994 | 0 | } |
995 | | |
996 | 0 | dev->color_info.polarity = |
997 | 0 | dci_std_polarity(dev->color_info.num_components); |
998 | | |
999 | | /* Adjust black levels */ |
1000 | 0 | if (eprn->colour_model == eprn_DeviceCMY || |
1001 | 0 | eprn->colour_model == eprn_DeviceRGB) { |
1002 | 0 | if (eprn->black_levels != 0) eprn->black_levels = 0; |
1003 | 0 | } |
1004 | 0 | else |
1005 | 0 | if (eprn->black_levels == 0) eprn->black_levels = 2; |
1006 | | /* Adjust non-black levels if they are too small for colour */ |
1007 | 0 | if (dev->color_info.num_components > 1 && eprn->non_black_levels <= 0) |
1008 | 0 | eprn->non_black_levels = 2; |
1009 | | |
1010 | | /* Adjustments to pixel depth, 'max_gray', 'max_color' and dither levels |
1011 | | will occur near the end of this routine */ |
1012 | 0 | } |
1013 | | |
1014 | | /* BlackLevels. Various depending values will be adjusted below. */ |
1015 | 0 | if ((rc = param_read_int(plist, (pname = "BlackLevels"), &temp)) == 0) { |
1016 | 0 | if ((temp == 0 && (eprn->colour_model == eprn_DeviceRGB || |
1017 | 0 | eprn->colour_model == eprn_DeviceCMY)) || |
1018 | 0 | (2 <= temp && temp <= 256 && |
1019 | 0 | eprn->colour_model != eprn_DeviceRGB && |
1020 | 0 | eprn->colour_model != eprn_DeviceCMY)) { |
1021 | 0 | if (eprn->black_levels != temp && dev->is_open) gs_closedevice(dev); |
1022 | 0 | eprn->black_levels = temp; |
1023 | 0 | } |
1024 | 0 | else { |
1025 | 0 | eprintf2("%s" ERRPREF |
1026 | 0 | "The value for BlackLevels is outside the range permitted: %d.\n", |
1027 | 0 | epref, temp); |
1028 | 0 | last_error = gs_error_rangecheck; |
1029 | 0 | param_signal_error(plist, pname, last_error); |
1030 | 0 | } |
1031 | 0 | } |
1032 | 0 | else if (rc < 0) last_error = rc; |
1033 | | |
1034 | | /* CMYLevels */ |
1035 | 0 | if ((rc = param_read_int(plist, (pname = "CMYLevels"), &temp)) == 0) { |
1036 | 0 | if ((temp == 0 && eprn->colour_model == eprn_DeviceGray) || |
1037 | 0 | (2 <= temp && temp <= 256 && eprn->colour_model != eprn_DeviceGray)) { |
1038 | 0 | if (eprn->non_black_levels != temp && dev->is_open) gs_closedevice(dev); |
1039 | 0 | eprn->non_black_levels = temp; |
1040 | 0 | } |
1041 | 0 | else { |
1042 | 0 | eprintf2("%s" ERRPREF |
1043 | 0 | "The value for CMYLevels is outside the range permitted: %d.\n", |
1044 | 0 | epref, temp); |
1045 | 0 | last_error = gs_error_rangecheck; |
1046 | 0 | param_signal_error(plist, pname, last_error); |
1047 | 0 | } |
1048 | 0 | } |
1049 | 0 | else if (rc < 0) last_error = rc; |
1050 | | |
1051 | | /* CUPS page accounting messages */ |
1052 | 0 | { |
1053 | 0 | bool temp; |
1054 | 0 | if ((rc = param_read_bool(plist, "CUPSAccounting", &temp)) == 0) { |
1055 | 0 | if (eprn->CUPS_accounting && !temp) |
1056 | 0 | eprintf(CUPS_WARNPREF WARNPREF |
1057 | 0 | "Attempt to set CUPSAccounting from true to false.\n"); |
1058 | 0 | else eprn->CUPS_accounting = temp; |
1059 | 0 | } |
1060 | 0 | else if (rc < 0) last_error = rc; |
1061 | 0 | } |
1062 | | |
1063 | | /* Intensity rendering */ |
1064 | 0 | if ((rc = param_read_string(plist, (pname = "IntensityRendering"), |
1065 | 0 | &string_value)) == 0) { |
1066 | 0 | rc = eprn_get_int(&string_value, intensity_rendering_list, &temp); |
1067 | 0 | if (rc == 0) { |
1068 | 0 | if (temp != eprn->intensity_rendering && dev->is_open) |
1069 | 0 | gs_closedevice(dev); |
1070 | 0 | eprn->intensity_rendering = temp; |
1071 | 0 | } |
1072 | 0 | else { |
1073 | 0 | eprintf1("%s" ERRPREF "Invalid method for IntensityRendering: `", |
1074 | 0 | epref); |
1075 | 0 | errwrite(dev->memory, (const char *)string_value.data, sizeof(char)*string_value.size); |
1076 | 0 | eprintf("'.\n"); |
1077 | 0 | last_error = gs_error_rangecheck; |
1078 | 0 | param_signal_error(plist, pname, last_error); |
1079 | 0 | } |
1080 | 0 | } |
1081 | 0 | else if (rc < 0) last_error = rc; |
1082 | | |
1083 | | /* Leading edge */ |
1084 | 0 | if ((rc = param_read_null(plist, (pname = "LeadingEdge"))) == 0) { |
1085 | 0 | if (eprn->leading_edge_set && dev->is_open) gs_closedevice(dev); |
1086 | 0 | eprn->leading_edge_set = false; |
1087 | 0 | } |
1088 | 0 | else if (rc < 0 && rc != gs_error_typecheck) last_error = rc; |
1089 | 0 | else if ((rc = param_read_int(plist, (pname = "LeadingEdge"), &temp)) == 0) { |
1090 | 0 | if (0 <= temp && temp <= 3) { |
1091 | 0 | if ((!eprn->leading_edge_set || eprn->default_orientation != temp) && |
1092 | 0 | dev->is_open) gs_closedevice(dev); |
1093 | 0 | eprn->leading_edge_set = true; |
1094 | 0 | eprn->default_orientation = temp; |
1095 | 0 | } |
1096 | 0 | else { |
1097 | 0 | eprintf2( |
1098 | 0 | "%s" ERRPREF "LeadingEdge may only have values 0 to 3, not %d.\n", |
1099 | 0 | epref, temp); |
1100 | 0 | last_error = gs_error_rangecheck; |
1101 | 0 | param_signal_error(plist, pname, last_error); |
1102 | 0 | } |
1103 | 0 | } |
1104 | 0 | else if (rc < 0) last_error = rc; |
1105 | | |
1106 | | /* Media configuration file */ |
1107 | 0 | if ((rc = param_read_null(plist, (pname = "MediaConfigurationFile"))) == 0) { |
1108 | 0 | if (eprn->media_file != NULL && dev->is_open) gs_closedevice(dev); |
1109 | 0 | rc = eprn_set_media_data((eprn_Device *)dev, NULL, 0); |
1110 | 0 | } |
1111 | 0 | else if (rc < 0 && rc != gs_error_typecheck) last_error = rc; |
1112 | 0 | else if ((rc = param_read_string(plist, pname, &string_value)) == 0) { |
1113 | 0 | if (string_value.size > 0) { |
1114 | 0 | if ((eprn->media_file == NULL || |
1115 | 0 | strncmp(eprn->media_file, (const char *)string_value.data, |
1116 | 0 | string_value.size) != 0 || |
1117 | 0 | eprn->media_file[string_value.size] != '\0') && dev->is_open) |
1118 | 0 | gs_closedevice(dev); |
1119 | 0 | rc = eprn_set_media_data((eprn_Device *)dev, |
1120 | 0 | (const char *)string_value.data, string_value.size); |
1121 | 0 | } |
1122 | 0 | else { |
1123 | 0 | if (eprn->media_file != NULL && dev->is_open) gs_closedevice(dev); |
1124 | 0 | rc = eprn_set_media_data((eprn_Device *)dev, NULL, 0); |
1125 | 0 | } |
1126 | |
|
1127 | 0 | if (rc != 0) { |
1128 | 0 | last_error = rc; |
1129 | 0 | param_signal_error(plist, pname, last_error); |
1130 | 0 | } |
1131 | 0 | } |
1132 | 0 | else if (rc < 0) last_error = rc; |
1133 | |
|
1134 | 0 | #ifndef EPRN_GS_HAS_MEDIAPOSITION |
1135 | 0 | if ((rc = param_read_null(plist, (pname = "MediaPosition"))) == 0) |
1136 | 0 | eprn->media_position_set = false; |
1137 | 0 | else if (rc < 0 && (rc = param_read_int(plist, pname, &eprn->media_position)) |
1138 | 0 | == 0) { |
1139 | | /* Current (up to at least gs 6.50) ghostscript versions do not accept |
1140 | | negative MediaPosition values. */ |
1141 | 0 | if (eprn->media_position < 0) |
1142 | 0 | eprintf3("%s" WARNPREF |
1143 | 0 | "Ghostscript does not accept negative values (%d) for the\n" |
1144 | 0 | "%s `MediaPosition' parameter.\n", |
1145 | 0 | wpref, eprn->media_position, wpref); |
1146 | | /* The error message is left for ghostscript to generate during input |
1147 | | media selection, should such an entry be a match. */ |
1148 | 0 | eprn->media_position_set = true; |
1149 | 0 | } |
1150 | 0 | else if (rc < 0) last_error = rc; |
1151 | 0 | #endif /* EPRN_GS_HAS_MEDIAPOSITION */ |
1152 | |
|
1153 | 0 | #ifndef EPRN_NO_PAGECOUNTFILE |
1154 | | /* Page count file */ |
1155 | 0 | if ((rc = param_read_null(plist, (pname = "PageCountFile"))) == 0) { |
1156 | 0 | if (eprn->pagecount_file != NULL) { |
1157 | 0 | gs_free(dev->memory->non_gc_memory, eprn->pagecount_file, strlen(eprn->pagecount_file) + 1, |
1158 | 0 | sizeof(char), "eprn_put_params"); |
1159 | 0 | eprn->pagecount_file = NULL; |
1160 | 0 | } |
1161 | 0 | } |
1162 | 0 | else if (rc < 0 && rc != gs_error_typecheck) last_error = rc; |
1163 | 0 | else if ((rc = param_read_string(plist, pname, &string_value)) == 0) { |
1164 | | /* Free old storage */ |
1165 | 0 | if (eprn->pagecount_file != NULL) { |
1166 | 0 | gs_free(dev->memory->non_gc_memory, eprn->pagecount_file, strlen(eprn->pagecount_file) + 1, |
1167 | 0 | sizeof(char), "eprn_put_params"); |
1168 | 0 | eprn->pagecount_file = NULL; |
1169 | 0 | } |
1170 | | |
1171 | | /* Store file name unless it is the empty string */ |
1172 | 0 | if (string_value.size > 0) { |
1173 | 0 | eprn->pagecount_file = (char *)gs_malloc(dev->memory->non_gc_memory, string_value.size + 1, |
1174 | 0 | sizeof(char), "eprn_put_params"); |
1175 | 0 | if (eprn->pagecount_file == NULL) { |
1176 | 0 | eprintf1( "%s" ERRPREF |
1177 | 0 | "Memory allocation failure from gs_malloc() in eprn_put_params().\n", |
1178 | 0 | epref); |
1179 | 0 | last_error = gs_error_VMerror; |
1180 | 0 | param_signal_error(plist, pname, last_error); |
1181 | 0 | } |
1182 | 0 | else { |
1183 | 0 | strncpy(eprn->pagecount_file, (const char *)string_value.data, |
1184 | 0 | string_value.size); |
1185 | 0 | eprn->pagecount_file[string_value.size] = '\0'; |
1186 | 0 | } |
1187 | 0 | } |
1188 | 0 | } |
1189 | 0 | #endif /* EPRN_NO_PAGECOUNTFILE */ |
1190 | | |
1191 | | /* RGBLevels */ |
1192 | 0 | if ((rc = param_read_int(plist, (pname = "RGBLevels"), &temp)) == 0) { |
1193 | 0 | if (temp == 0 || (2 <= temp && temp <= 256)) { |
1194 | 0 | if (eprn->non_black_levels != temp && dev->is_open) gs_closedevice(dev); |
1195 | 0 | eprn->non_black_levels = temp; |
1196 | 0 | } |
1197 | 0 | else { |
1198 | 0 | eprintf2("%s" ERRPREF |
1199 | 0 | "The value for RGBLevels is outside the range permitted: %d.\n", |
1200 | 0 | epref, temp); |
1201 | 0 | last_error = gs_error_rangecheck; |
1202 | 0 | param_signal_error(plist, pname, last_error); |
1203 | 0 | } |
1204 | 0 | } |
1205 | 0 | else if (rc < 0) last_error = rc; |
1206 | | |
1207 | | /* Determine various derived colour parameters */ |
1208 | 0 | set_derived_colour_data((eprn_Device *)dev); |
1209 | | |
1210 | | /* Catch a specification of BitsPerPixel --- otherwise a wrong value gives |
1211 | | just a rangecheck error from gs without any readily understandable |
1212 | | information (see gx_default_put_params()). This confused one hpdj user |
1213 | | so much that he wrote in a newsgroup that gs was dumping core in this |
1214 | | case :-). |
1215 | | */ |
1216 | 0 | if ((rc = param_read_int(plist, (pname = "BitsPerPixel"), &temp)) == 0) { |
1217 | 0 | if (temp != dev->color_info.depth) { |
1218 | 0 | eprintf3("%s" ERRPREF |
1219 | 0 | "Attempt to set `BitsPerPixel' to a value (%d)\n" |
1220 | 0 | "%s other than the one selected by the driver.\n", |
1221 | 0 | epref, temp, epref); |
1222 | 0 | last_error = gs_error_rangecheck; |
1223 | 0 | param_signal_error(plist, pname, last_error); |
1224 | 0 | } |
1225 | 0 | } else if (rc < 0) last_error = rc; |
1226 | | |
1227 | | /* Check whether ".HWMargins" is specified and, if it is, refrain from |
1228 | | overwriting it. */ |
1229 | 0 | { |
1230 | 0 | gs_param_typed_value temp; |
1231 | 0 | if (param_read_typed(plist, ".HWMargins", &temp) == 0) { |
1232 | | /* ".HWMargins" is specified */ |
1233 | | #ifdef EPRN_TRACE |
1234 | | if_debug1(EPRN_TRACE_CHAR, "! .HWMargins is specified: type is %d.\n", |
1235 | | (int)temp.type); |
1236 | | #endif |
1237 | 0 | eprn->keep_margins = true; |
1238 | 0 | } |
1239 | 0 | } |
1240 | | |
1241 | | /* Process parameters defined by base classes (should occur after treating |
1242 | | parameters defined for the derived class, see gsparam.h) */ |
1243 | 0 | rc = gdev_prn_put_params(dev, plist); |
1244 | 0 | if (rc < 0 || (rc > 0 && last_error >= 0)) |
1245 | 0 | last_error = rc; |
1246 | |
|
1247 | 0 | if (last_error < 0) return_error(last_error); |
1248 | | |
1249 | | /* If the page size was modified, close the device */ |
1250 | 0 | if (dev->is_open && (dev->width != width || dev->height != height || |
1251 | 0 | mediasize[0] != dev->MediaSize[0] || mediasize[1] != dev->MediaSize[1])) { |
1252 | 0 | gs_closedevice(dev); |
1253 | | #ifdef EPRN_TRACE |
1254 | | if_debug0(EPRN_TRACE_CHAR, |
1255 | | "! Closing device because of page size modification.\n"); |
1256 | | #endif |
1257 | 0 | } |
1258 | |
|
1259 | 0 | return last_error; |
1260 | 0 | } |