1 /* Copyright (C) 1989, 2000 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: gsdevice.c,v 1.25 2005/10/12 17:59:55 leonardo Exp $ */
18 /* Device operators for Ghostscript library */
19 #include "ctype_.h"
20 #include "memory_.h" /* for memchr, memcpy */
21 #include "string_.h"
22 #include "gx.h"
23 #include "gp.h"
24 #include "gscdefs.h" /* for gs_lib_device_list */
25 #include "gserrors.h"
26 #include "gsfname.h"
27 #include "gsstruct.h"
28 #include "gspath.h" /* gs_initclip prototype */
29 #include "gspaint.h" /* gs_erasepage prototype */
30 #include "gsmatrix.h" /* for gscoord.h */
31 #include "gscoord.h" /* for gs_initmatrix */
32 #include "gzstate.h"
33 #include "gxcmap.h"
34 #include "gxdevice.h"
35 #include "gxdevmem.h"
36 #include "gxiodev.h"
37 #include "gxcspace.h"
38
39 /* Include the extern for the device list. */
40 extern_gs_lib_device_list();
41
42 /*
43 * Finalization for devices: do any special finalization first, then
44 * close the device if it is open, and finally free the structure
45 * descriptor if it is dynamic.
46 */
47 void
gx_device_finalize(void * vptr)48 gx_device_finalize(void *vptr)
49 {
50 gx_device * const dev = (gx_device *)vptr;
51
52 if (dev->finalize)
53 dev->finalize(dev);
54 discard(gs_closedevice(dev));
55 if (dev->stype_is_dynamic)
56 gs_free_const_object(dev->memory->non_gc_memory, dev->stype,
57 "gx_device_finalize");
58 }
59
60 /* "Free" a device locally allocated on the stack, by finalizing it. */
61 void
gx_device_free_local(gx_device * dev)62 gx_device_free_local(gx_device *dev)
63 {
64 gx_device_finalize(dev);
65 }
66
67 /* GC procedures */
68 private
69 ENUM_PTRS_WITH(device_forward_enum_ptrs, gx_device_forward *fdev) return 0;
70 case 0: ENUM_RETURN(gx_device_enum_ptr(fdev->target));
71 ENUM_PTRS_END
RELOC_PTRS_WITH(device_forward_reloc_ptrs,gx_device_forward * fdev)72 private RELOC_PTRS_WITH(device_forward_reloc_ptrs, gx_device_forward *fdev)
73 {
74 fdev->target = gx_device_reloc_ptr(fdev->target, gcst);
75 }
76 RELOC_PTRS_END
77
78 /*
79 * Structure descriptors. These must follow the procedures, because
80 * we can't conveniently forward-declare the procedures.
81 * (See gxdevice.h for details.)
82 */
83 public_st_device();
84 public_st_device_forward();
85 public_st_device_null();
86
87 /* GC utilities */
88 /* Enumerate or relocate a device pointer for a client. */
89 gx_device *
gx_device_enum_ptr(gx_device * dev)90 gx_device_enum_ptr(gx_device * dev)
91 {
92 if (dev == 0 || dev->memory == 0)
93 return 0;
94 return dev;
95 }
96 gx_device *
gx_device_reloc_ptr(gx_device * dev,gc_state_t * gcst)97 gx_device_reloc_ptr(gx_device * dev, gc_state_t * gcst)
98 {
99 if (dev == 0 || dev->memory == 0)
100 return dev;
101 return RELOC_OBJ(dev); /* gcst implicit */
102 }
103
104 /* Set up the device procedures in the device structure. */
105 /* Also copy old fields to new ones. */
106 void
gx_device_set_procs(gx_device * dev)107 gx_device_set_procs(gx_device * dev)
108 {
109 if (dev->static_procs != 0) { /* 0 if already populated */
110 dev->procs = *dev->static_procs;
111 dev->static_procs = 0;
112 }
113 }
114
115 /* Flush buffered output to the device */
116 int
gs_flushpage(gs_state * pgs)117 gs_flushpage(gs_state * pgs)
118 {
119 gx_device *dev = gs_currentdevice(pgs);
120
121 return (*dev_proc(dev, sync_output)) (dev);
122 }
123
124 /* Make the device output the accumulated page description */
125 int
gs_copypage(gs_state * pgs)126 gs_copypage(gs_state * pgs)
127 {
128 return gs_output_page(pgs, 1, 0);
129 }
130 int
gs_output_page(gs_state * pgs,int num_copies,int flush)131 gs_output_page(gs_state * pgs, int num_copies, int flush)
132 {
133 gx_device *dev = gs_currentdevice(pgs);
134
135 if (dev->IgnoreNumCopies)
136 num_copies = 1;
137 return (*dev_proc(dev, output_page)) (dev, num_copies, flush);
138 }
139
140 /*
141 * Do generic work for output_page. All output_page procedures must call
142 * this as the last thing they do, unless an error has occurred earlier.
143 */
144 int
gx_finish_output_page(gx_device * dev,int num_copies,int flush)145 gx_finish_output_page(gx_device *dev, int num_copies, int flush)
146 {
147 dev->PageCount += num_copies;
148 return 0;
149 }
150
151 /* Copy scan lines from an image device */
152 int
gs_copyscanlines(gx_device * dev,int start_y,byte * data,uint size,int * plines_copied,uint * pbytes_copied)153 gs_copyscanlines(gx_device * dev, int start_y, byte * data, uint size,
154 int *plines_copied, uint * pbytes_copied)
155 {
156 uint line_size = gx_device_raster(dev, 0);
157 uint count = size / line_size;
158 uint i;
159 byte *dest = data;
160
161 for (i = 0; i < count; i++, dest += line_size) {
162 int code = (*dev_proc(dev, get_bits)) (dev, start_y + i, dest, NULL);
163
164 if (code < 0) {
165 /* Might just be an overrun. */
166 if (start_y + i == dev->height)
167 break;
168 return_error(code);
169 }
170 }
171 if (plines_copied != NULL)
172 *plines_copied = i;
173 if (pbytes_copied != NULL)
174 *pbytes_copied = i * line_size;
175 return 0;
176 }
177
178 /* Get the current device from the graphics state. */
179 gx_device *
gs_currentdevice(const gs_state * pgs)180 gs_currentdevice(const gs_state * pgs)
181 {
182 return pgs->device;
183 }
184
185 /* Get the name of a device. */
186 const char *
gs_devicename(const gx_device * dev)187 gs_devicename(const gx_device * dev)
188 {
189 return dev->dname;
190 }
191
192 /* Get the initial matrix of a device. */
193 void
gs_deviceinitialmatrix(gx_device * dev,gs_matrix * pmat)194 gs_deviceinitialmatrix(gx_device * dev, gs_matrix * pmat)
195 {
196 fill_dev_proc(dev, get_initial_matrix, gx_default_get_initial_matrix);
197 (*dev_proc(dev, get_initial_matrix)) (dev, pmat);
198 }
199
200 /* Get the N'th device from the known device list */
201 const gx_device *
gs_getdevice(int index)202 gs_getdevice(int index)
203 {
204 const gx_device *const *list;
205 int count = gs_lib_device_list(&list, NULL);
206
207 if (index < 0 || index >= count)
208 return 0; /* index out of range */
209 return list[index];
210 }
211
212 /* Fill in the GC structure descriptor for a device. */
213 private void
gx_device_make_struct_type(gs_memory_struct_type_t * st,const gx_device * dev)214 gx_device_make_struct_type(gs_memory_struct_type_t *st,
215 const gx_device *dev)
216 {
217 const gx_device_procs *procs = dev->static_procs;
218
219 /*
220 * Try to figure out whether this is a forwarding device. For printer
221 * devices, we rely on the prototype referencing the correct structure
222 * descriptor; for other devices, we look for a likely forwarding
223 * procedure in the vector. The algorithm isn't foolproof, but it's the
224 * best we can come up with.
225 */
226 if (procs == 0)
227 procs = &dev->procs;
228 if (dev->stype)
229 *st = *dev->stype;
230 else if (procs->get_xfont_procs == gx_forward_get_xfont_procs)
231 *st = st_device_forward;
232 else
233 *st = st_device;
234 st->ssize = dev->params_size;
235 }
236
237 /* Clone an existing device. */
238 int
gs_copydevice2(gx_device ** pnew_dev,const gx_device * dev,bool keep_open,gs_memory_t * mem)239 gs_copydevice2(gx_device ** pnew_dev, const gx_device * dev, bool keep_open,
240 gs_memory_t * mem)
241 {
242 gx_device *new_dev;
243 const gs_memory_struct_type_t *std = dev->stype;
244 const gs_memory_struct_type_t *new_std;
245 gs_memory_struct_type_t *a_std = 0;
246 int code;
247
248 if (dev->stype_is_dynamic) {
249 /*
250 * We allocated the stype for this device previously.
251 * Just allocate a new stype and copy the old one into it.
252 */
253 a_std = (gs_memory_struct_type_t *)
254 gs_alloc_bytes_immovable(mem->non_gc_memory, sizeof(*std),
255 "gs_copydevice(stype)");
256 if (!a_std)
257 return_error(gs_error_VMerror);
258 *a_std = *std;
259 new_std = a_std;
260 } else if (std != 0 && std->ssize == dev->params_size) {
261 /* Use the static stype. */
262 new_std = std;
263 } else {
264 /* We need to figure out or adjust the stype. */
265 a_std = (gs_memory_struct_type_t *)
266 gs_alloc_bytes_immovable(mem->non_gc_memory, sizeof(*std),
267 "gs_copydevice(stype)");
268 if (!a_std)
269 return_error(gs_error_VMerror);
270 gx_device_make_struct_type(a_std, dev);
271 new_std = a_std;
272 }
273 /*
274 * Because command list devices have complicated internal pointer
275 * structures, we allocate all device instances as immovable.
276 */
277 new_dev = gs_alloc_struct_immovable(mem, gx_device, new_std,
278 "gs_copydevice(device)");
279 if (new_dev == 0)
280 return_error(gs_error_VMerror);
281 gx_device_init(new_dev, dev, mem, false);
282 gx_device_set_procs(new_dev);
283 new_dev->stype = new_std;
284 new_dev->stype_is_dynamic = new_std != std;
285 /*
286 * keep_open is very dangerous. On the other hand, so is copydevice in
287 * general, since it just copies the bits without any regard to pointers
288 * (including self-pointers) that they may contain. We handle this by
289 * making the default finish_copydevice forbid copying of anything other
290 * than the device prototype.
291 */
292 new_dev->is_open = dev->is_open && keep_open;
293 fill_dev_proc(new_dev, finish_copydevice, gx_default_finish_copydevice);
294 code = dev_proc(new_dev, finish_copydevice)(new_dev, dev);
295 if (code < 0) {
296 gs_free_object(mem, new_dev, "gs_copydevice(device)");
297 if (a_std)
298 gs_free_object(dev->memory->non_gc_memory, a_std, "gs_copydevice(stype)");
299 return code;
300 }
301 *pnew_dev = new_dev;
302 return 0;
303 }
304 int
gs_copydevice(gx_device ** pnew_dev,const gx_device * dev,gs_memory_t * mem)305 gs_copydevice(gx_device ** pnew_dev, const gx_device * dev, gs_memory_t * mem)
306 {
307 return gs_copydevice2(pnew_dev, dev, false, mem);
308 }
309
310 /* Open a device if not open already. Return 0 if the device was open, */
311 /* 1 if it was closed. */
312 int
gs_opendevice(gx_device * dev)313 gs_opendevice(gx_device *dev)
314 {
315 if (dev->is_open)
316 return 0;
317 check_device_separable(dev);
318 gx_device_fill_in_procs(dev);
319 {
320 int code = (*dev_proc(dev, open_device))(dev);
321
322 if (code < 0)
323 return_error(code);
324 dev->is_open = true;
325 return 1;
326 }
327 }
328
329 /* Set device parameters, updating a graphics state or imager state. */
330 int
gs_imager_putdeviceparams(gs_imager_state * pis,gx_device * dev,gs_param_list * plist)331 gs_imager_putdeviceparams(gs_imager_state *pis, gx_device *dev,
332 gs_param_list *plist)
333 {
334 int code = gs_putdeviceparams(dev, plist);
335
336 if (code >= 0)
337 gx_set_cmap_procs(pis, dev);
338 return code;
339 }
340 private void
gs_state_update_device(gs_state * pgs)341 gs_state_update_device(gs_state *pgs)
342 {
343 gx_set_cmap_procs((gs_imager_state *)pgs, pgs->device);
344 gx_unset_dev_color(pgs);
345 }
346 int
gs_state_putdeviceparams(gs_state * pgs,gs_param_list * plist)347 gs_state_putdeviceparams(gs_state *pgs, gs_param_list *plist)
348 {
349 int code = gs_putdeviceparams(pgs->device, plist);
350
351 if (code >= 0)
352 gs_state_update_device(pgs);
353 return code;
354 }
355
356 /* Set the device in the graphics state */
357 int
gs_setdevice(gs_state * pgs,gx_device * dev)358 gs_setdevice(gs_state * pgs, gx_device * dev)
359 {
360 int code = gs_setdevice_no_erase(pgs, dev);
361
362 if (code == 1)
363 code = gs_erasepage(pgs);
364 return code;
365 }
366 int
gs_setdevice_no_erase(gs_state * pgs,gx_device * dev)367 gs_setdevice_no_erase(gs_state * pgs, gx_device * dev)
368 {
369 int open_code = 0, code;
370
371 /* Initialize the device */
372 if (!dev->is_open) {
373 gx_device_fill_in_procs(dev);
374 if (gs_device_is_memory(dev)) {
375 /* Set the target to the current device. */
376 gx_device *odev = gs_currentdevice_inline(pgs);
377
378 while (odev != 0 && gs_device_is_memory(odev))
379 odev = ((gx_device_memory *)odev)->target;
380 gx_device_set_target(((gx_device_forward *)dev), odev);
381 }
382 code = open_code = gs_opendevice(dev);
383 if (code < 0)
384 return code;
385 }
386 gs_setdevice_no_init(pgs, dev);
387 pgs->ctm_default_set = false;
388 if ((code = gs_initmatrix(pgs)) < 0 ||
389 (code = gs_initclip(pgs)) < 0
390 )
391 return code;
392 /* If we were in a charpath or a setcachedevice, */
393 /* we aren't any longer. */
394 pgs->in_cachedevice = 0;
395 pgs->in_charpath = (gs_char_path_mode) 0;
396 return open_code;
397 }
398 int
gs_setdevice_no_init(gs_state * pgs,gx_device * dev)399 gs_setdevice_no_init(gs_state * pgs, gx_device * dev)
400 {
401 /*
402 * Just set the device, possibly changing color space but no other
403 * device parameters.
404 *
405 * Make sure we don't close the device if dev == pgs->device
406 * This could be done by allowing the rc_assign to close the
407 * old 'dev' if the rc goes to 0 (via the device structure's
408 * finalization procedure), but then the 'code' from the dev
409 * closedevice would not be propagated up. We want to allow
410 * the code to be handled, particularly for the pdfwrite
411 * device.
412 */
413 if (pgs->device != NULL && pgs->device->rc.ref_count == 1 &&
414 pgs->device != dev) {
415 int code = gs_closedevice(pgs->device);
416
417 if (code < 0)
418 return code;
419 }
420 rc_assign(pgs->device, dev, "gs_setdevice_no_init");
421 gs_state_update_device(pgs);
422 return pgs->overprint ? gs_do_set_overprint(pgs) : 0;
423 }
424
425 /* Initialize a just-allocated device. */
426 void
gx_device_init(gx_device * dev,const gx_device * proto,gs_memory_t * mem,bool internal)427 gx_device_init(gx_device * dev, const gx_device * proto, gs_memory_t * mem,
428 bool internal)
429 {
430 memcpy(dev, proto, proto->params_size);
431 dev->memory = mem;
432 dev->retained = !internal;
433 rc_init(dev, mem, (internal ? 0 : 1));
434 }
435
436 /* Make a null device. */
437 void
gs_make_null_device(gx_device_null * dev_null,gx_device * dev,gs_memory_t * mem)438 gs_make_null_device(gx_device_null *dev_null, gx_device *dev,
439 gs_memory_t * mem)
440 {
441 gx_device_init((gx_device *)dev_null, (const gx_device *)&gs_null_device,
442 mem, true);
443 gx_device_set_target((gx_device_forward *)dev_null, dev);
444 if (dev) {
445 /* The gx_device_copy_color_params() call below should
446 probably copy over these new-style color mapping procs, as
447 well as the old-style (map_rgb_color and friends). However,
448 the change was made here instead, to minimize the potential
449 impact of the patch.
450 */
451 gx_device *dn = (gx_device *)dev_null;
452 set_dev_proc(dn, get_color_mapping_procs, gx_forward_get_color_mapping_procs);
453 set_dev_proc(dn, get_color_comp_index, gx_forward_get_color_comp_index);
454 set_dev_proc(dn, encode_color, gx_forward_encode_color);
455 set_dev_proc(dn, decode_color, gx_forward_decode_color);
456 gx_device_copy_color_params(dn, dev);
457 }
458 }
459
460 /* Is a null device ? */
gs_is_null_device(gx_device * dev)461 bool gs_is_null_device(gx_device *dev)
462 {
463 /* Assuming null_fill_path isn't used elswhere. */
464 return dev->procs.fill_path == gs_null_device.procs.fill_path;
465 }
466
467 /* Mark a device as retained or not retained. */
468 void
gx_device_retain(gx_device * dev,bool retained)469 gx_device_retain(gx_device *dev, bool retained)
470 {
471 int delta = (int)retained - (int)dev->retained;
472
473 if (delta) {
474 dev->retained = retained; /* do first in case dev is freed */
475 rc_adjust_only(dev, delta, "gx_device_retain");
476 }
477 }
478
479 /* Select a null device. */
480 int
gs_nulldevice(gs_state * pgs)481 gs_nulldevice(gs_state * pgs)
482 {
483 if (pgs->device == 0 || !gx_device_is_null(pgs->device)) {
484 gx_device *ndev;
485 int code = gs_copydevice(&ndev, (const gx_device *)&gs_null_device,
486 pgs->memory);
487
488 if (code < 0)
489 return code;
490 /*
491 * Internal devices have a reference count of 0, not 1,
492 * aside from references from graphics states.
493 */
494 rc_init(ndev, pgs->memory, 0);
495 return gs_setdevice_no_erase(pgs, ndev);
496 }
497 return 0;
498 }
499
500 /* Close a device. The client is responsible for ensuring that */
501 /* this device is not current in any graphics state. */
502 int
gs_closedevice(gx_device * dev)503 gs_closedevice(gx_device * dev)
504 {
505 int code = 0;
506
507 if (dev->is_open) {
508 code = (*dev_proc(dev, close_device))(dev);
509 dev->is_open = false;
510 if (code < 0)
511 return_error(code);
512 }
513 return code;
514 }
515
516 /*
517 * Just set the device without any reinitializing.
518 * (For internal use only.)
519 */
520 void
gx_set_device_only(gs_state * pgs,gx_device * dev)521 gx_set_device_only(gs_state * pgs, gx_device * dev)
522 {
523 rc_assign(pgs->device, dev, "gx_set_device_only");
524 }
525
526 /* Compute the size of one scan line for a device, */
527 /* with or without padding to a word boundary. */
528 uint
gx_device_raster(const gx_device * dev,bool pad)529 gx_device_raster(const gx_device * dev, bool pad)
530 {
531 ulong bits = (ulong) dev->width * dev->color_info.depth;
532
533 return (pad ? bitmap_raster(bits) : (uint) ((bits + 7) >> 3));
534 }
535
536 /* Adjust the resolution for devices that only have a fixed set of */
537 /* geometries, so that the apparent size in inches remains constant. */
538 /* If fit=1, the resolution is adjusted so that the entire image fits; */
539 /* if fit=0, one dimension fits, but the other one is clipped. */
540 int
gx_device_adjust_resolution(gx_device * dev,int actual_width,int actual_height,int fit)541 gx_device_adjust_resolution(gx_device * dev,
542 int actual_width, int actual_height, int fit)
543 {
544 double width_ratio = (double)actual_width / dev->width;
545 double height_ratio = (double)actual_height / dev->height;
546 double ratio =
547 (fit ? min(width_ratio, height_ratio) :
548 max(width_ratio, height_ratio));
549
550 dev->HWResolution[0] *= ratio;
551 dev->HWResolution[1] *= ratio;
552 gx_device_set_width_height(dev, actual_width, actual_height);
553 return 0;
554 }
555
556 /* Set the HWMargins to values defined in inches. */
557 /* If move_origin is true, also reset the Margins. */
558 /* Note that this assumes a printer-type device (Y axis inverted). */
559 void
gx_device_set_margins(gx_device * dev,const float * margins,bool move_origin)560 gx_device_set_margins(gx_device * dev, const float *margins /*[4] */ ,
561 bool move_origin)
562 {
563 int i;
564
565 for (i = 0; i < 4; ++i)
566 dev->HWMargins[i] = margins[i] * 72.0;
567 if (move_origin) {
568 dev->Margins[0] = -margins[0] * dev->MarginsHWResolution[0];
569 dev->Margins[1] = -margins[3] * dev->MarginsHWResolution[1];
570 }
571 }
572
573
574 /* Handle 90 and 270 degree rotation of the Tray
575 * Device must support TrayOrientation in its InitialMatrix and get/put params
576 */
577 private void
gx_device_TrayOrientationRotate(gx_device * dev)578 gx_device_TrayOrientationRotate(gx_device *dev)
579 {
580 if ( dev->TrayOrientation == 90 || dev->TrayOrientation == 270) {
581 /* page sizes don't rotate, height and width do rotate
582 * HWResolution, HWSize, and MediaSize parameters interact,
583 * and must be set before TrayOrientation
584 */
585 int tmp = dev->height;
586 dev->height = dev->width;
587 dev->width = tmp;
588 }
589 }
590
591 /* Set the width and height, updating MediaSize to remain consistent. */
592 void
gx_device_set_width_height(gx_device * dev,int width,int height)593 gx_device_set_width_height(gx_device * dev, int width, int height)
594 {
595 dev->width = width;
596 dev->height = height;
597 dev->MediaSize[0] = width * 72.0 / dev->HWResolution[0];
598 dev->MediaSize[1] = height * 72.0 / dev->HWResolution[1];
599 gx_device_TrayOrientationRotate(dev);
600 }
601
602 /* Set the resolution, updating width and height to remain consistent. */
603 void
gx_device_set_resolution(gx_device * dev,floatp x_dpi,floatp y_dpi)604 gx_device_set_resolution(gx_device * dev, floatp x_dpi, floatp y_dpi)
605 {
606 dev->HWResolution[0] = x_dpi;
607 dev->HWResolution[1] = y_dpi;
608 dev->width = (int)(dev->MediaSize[0] * x_dpi / 72.0 + 0.5);
609 dev->height = (int)(dev->MediaSize[1] * y_dpi / 72.0 + 0.5);
610 gx_device_TrayOrientationRotate(dev);
611 }
612
613 /* Set the MediaSize, updating width and height to remain consistent. */
614 void
gx_device_set_media_size(gx_device * dev,floatp media_width,floatp media_height)615 gx_device_set_media_size(gx_device * dev, floatp media_width, floatp media_height)
616 {
617 dev->MediaSize[0] = media_width;
618 dev->MediaSize[1] = media_height;
619 dev->width = (int)(media_width * dev->HWResolution[0] / 72.0 + 0.499);
620 dev->height = (int)(media_height * dev->HWResolution[1] / 72.0 + 0.499);
621 gx_device_TrayOrientationRotate(dev);
622 }
623
624 /*
625 * Copy the color mapping procedures from the target if they are
626 * standard ones (saving a level of procedure call at mapping time).
627 */
628 void
gx_device_copy_color_procs(gx_device * dev,const gx_device * target)629 gx_device_copy_color_procs(gx_device *dev, const gx_device *target)
630 {
631 dev_proc_map_cmyk_color((*from_cmyk)) =
632 dev_proc(dev, map_cmyk_color);
633 dev_proc_map_rgb_color((*from_rgb)) =
634 dev_proc(dev, map_rgb_color);
635 dev_proc_map_color_rgb((*to_rgb)) =
636 dev_proc(dev, map_color_rgb);
637
638 /* The logic in this function seems a bit stale; it sets the
639 old-style color procs, but not the new ones
640 (get_color_mapping_procs, get_color_comp_index, encode_color,
641 and decode_color). It should probably copy those as well.
642 */
643 if (from_cmyk == gx_forward_map_cmyk_color ||
644 from_cmyk == cmyk_1bit_map_cmyk_color ||
645 from_cmyk == cmyk_8bit_map_cmyk_color) {
646 from_cmyk = dev_proc(target, map_cmyk_color);
647 set_dev_proc(dev, map_cmyk_color,
648 (from_cmyk == cmyk_1bit_map_cmyk_color ||
649 from_cmyk == cmyk_8bit_map_cmyk_color ?
650 from_cmyk : gx_forward_map_cmyk_color));
651 }
652 if (from_rgb == gx_forward_map_rgb_color ||
653 from_rgb == gx_default_rgb_map_rgb_color) {
654 from_rgb = dev_proc(target, map_rgb_color);
655 set_dev_proc(dev, map_rgb_color,
656 (from_rgb == gx_default_rgb_map_rgb_color ?
657 from_rgb : gx_forward_map_rgb_color));
658 }
659 if (to_rgb == gx_forward_map_color_rgb ||
660 to_rgb == cmyk_1bit_map_color_rgb ||
661 to_rgb == cmyk_8bit_map_color_rgb) {
662 to_rgb = dev_proc(target, map_color_rgb);
663 set_dev_proc(dev, map_color_rgb,
664 (to_rgb == cmyk_1bit_map_color_rgb ||
665 to_rgb == cmyk_8bit_map_color_rgb ?
666 to_rgb : gx_forward_map_color_rgb));
667 }
668 }
669
670 #define COPY_PARAM(p) dev->p = target->p
671
672 /*
673 * Copy the color-related device parameters back from the target:
674 * color_info and color mapping procedures.
675 */
676 void
gx_device_copy_color_params(gx_device * dev,const gx_device * target)677 gx_device_copy_color_params(gx_device *dev, const gx_device *target)
678 {
679 COPY_PARAM(color_info);
680 COPY_PARAM(cached_colors);
681 gx_device_copy_color_procs(dev, target);
682 }
683
684 /*
685 * Copy device parameters back from a target. This copies all standard
686 * parameters related to page size and resolution, plus color_info
687 * and (if appropriate) color mapping procedures.
688 */
689 void
gx_device_copy_params(gx_device * dev,const gx_device * target)690 gx_device_copy_params(gx_device *dev, const gx_device *target)
691 {
692 #define COPY_ARRAY_PARAM(p) memcpy(dev->p, target->p, sizeof(dev->p))
693 COPY_PARAM(width);
694 COPY_PARAM(height);
695 COPY_ARRAY_PARAM(MediaSize);
696 COPY_ARRAY_PARAM(ImagingBBox);
697 COPY_PARAM(ImagingBBox_set);
698 COPY_ARRAY_PARAM(HWResolution);
699 COPY_ARRAY_PARAM(MarginsHWResolution);
700 COPY_ARRAY_PARAM(Margins);
701 COPY_ARRAY_PARAM(HWMargins);
702 COPY_PARAM(PageCount);
703 #undef COPY_ARRAY_PARAM
704 gx_device_copy_color_params(dev, target);
705 }
706
707 #undef COPY_PARAM
708
709 /*
710 * Parse the output file name detecting and validating any %nnd format
711 * for inserting the page count. If a format is present, store a pointer
712 * to its last character in *pfmt, otherwise store 0 there.
713 * Note that we assume devices have already been scanned, and any % must
714 * precede a valid format character.
715 *
716 * If there was a format, then return the max_width
717 */
718 private int
gx_parse_output_format(gs_parsed_file_name_t * pfn,const char ** pfmt)719 gx_parse_output_format(gs_parsed_file_name_t *pfn, const char **pfmt)
720 {
721 bool have_format = false, field = 0;
722 int width[2], int_width = sizeof(int) * 3, w = 0;
723 uint i;
724
725 /* Scan the file name for a format string, and validate it if present. */
726 width[0] = width[1] = 0;
727 for (i = 0; i < pfn->len; ++i)
728 if (pfn->fname[i] == '%') {
729 if (i + 1 < pfn->len && pfn->fname[i + 1] == '%')
730 continue;
731 if (have_format) /* more than one % */
732 return_error(gs_error_undefinedfilename);
733 have_format = true;
734 sw:
735 if (++i == pfn->len)
736 return_error(gs_error_undefinedfilename);
737 switch (pfn->fname[i]) {
738 case 'l':
739 int_width = sizeof(long) * 3;
740 case ' ': case '#': case '+': case '-':
741 goto sw;
742 case '.':
743 if (field)
744 return_error(gs_error_undefinedfilename);
745 field = 1;
746 continue;
747 case '0': case '1': case '2': case '3': case '4':
748 case '5': case '6': case '7': case '8': case '9':
749 width[field] = width[field] * 10 + pfn->fname[i] - '0';
750 goto sw;
751 case 'd': case 'i': case 'u': case 'o': case 'x': case 'X':
752 *pfmt = &pfn->fname[i];
753 continue;
754 default:
755 return_error(gs_error_undefinedfilename);
756 }
757 }
758 if (have_format) {
759 /* Calculate a conservative maximum width. */
760 w = max(width[0], width[1]);
761 w = max(w, int_width) + 5;
762 }
763 return w;
764 }
765
766 /*
767 * Parse the output file name for a device, recognizing "-" and "|command",
768 * and also detecting and validating any %nnd format for inserting the
769 * page count. If a format is present, store a pointer to its last
770 * character in *pfmt, otherwise store 0 there. Note that an empty name
771 * is currently allowed.
772 */
773 int
gx_parse_output_file_name(gs_parsed_file_name_t * pfn,const char ** pfmt,const char * fname,uint fnlen)774 gx_parse_output_file_name(gs_parsed_file_name_t *pfn, const char **pfmt,
775 const char *fname, uint fnlen)
776 {
777 int code;
778
779 *pfmt = 0;
780 pfn->memory = 0;
781 pfn->iodev = NULL;
782 pfn->fname = NULL; /* irrelevant since length = 0 */
783 pfn->len = 0;
784 if (fnlen == 0) /* allow null name */
785 return 0;
786 /*
787 * If the file name begins with a %, it might be either an IODevice
788 * or a %nnd format. Check (carefully) for this case.
789 */
790 code = gs_parse_file_name(pfn, fname, fnlen);
791 if (code < 0) {
792 if (fname[0] == '%') {
793 /* not a recognized iodev -- may be a leading format descriptor */
794 pfn->len = fnlen;
795 pfn->fname = fname;
796 code = gx_parse_output_format(pfn, pfmt);
797 }
798 if (code < 0)
799 return code;
800 }
801 if (!pfn->iodev) {
802 if ( (pfn->len == 1) && (pfn->fname[0] == '-') ) {
803 pfn->iodev = gs_findiodevice((const byte *)"%stdout", 7);
804 pfn->fname = NULL;
805 } else if (pfn->fname[0] == '|') {
806 pfn->iodev = gs_findiodevice((const byte *)"%pipe", 5);
807 pfn->fname++, pfn->len--;
808 } else
809 pfn->iodev = iodev_default;
810 if (!pfn->iodev)
811 return_error(gs_error_undefinedfilename);
812 }
813 if (!pfn->fname)
814 return 0;
815 code = gx_parse_output_format(pfn, pfmt);
816 if (code < 0)
817 return code;
818 if (strlen(pfn->iodev->dname) + pfn->len + code >= gp_file_name_sizeof)
819 return_error(gs_error_undefinedfilename);
820 return 0;
821 }
822
823 /* Open the output file for a device. */
824 int
gx_device_open_output_file(const gx_device * dev,char * fname,bool binary,bool positionable,FILE ** pfile)825 gx_device_open_output_file(const gx_device * dev, char *fname,
826 bool binary, bool positionable, FILE ** pfile)
827 {
828 gs_parsed_file_name_t parsed;
829 const char *fmt;
830 char pfname[gp_file_name_sizeof];
831 int code = gx_parse_output_file_name(&parsed, &fmt, fname, strlen(fname));
832
833 if (code < 0)
834 return code;
835 if (parsed.iodev && !strcmp(parsed.iodev->dname, "%stdout%")) {
836 if (parsed.fname)
837 return_error(gs_error_undefinedfilename);
838 *pfile = dev->memory->gs_lib_ctx->fstdout;
839 /* Force stdout to binary. */
840 return gp_setmode_binary(*pfile, true);
841 }
842 if (fmt) {
843 long count1 = dev->PageCount + 1;
844
845 while (*fmt != 'l' && *fmt != '%')
846 --fmt;
847 if (*fmt == 'l')
848 sprintf(pfname, parsed.fname, count1);
849 else
850 sprintf(pfname, parsed.fname, (int)count1);
851 parsed.fname = pfname;
852 parsed.len = strlen(parsed.fname);
853 }
854 if (positionable || (parsed.iodev && parsed.iodev != iodev_default)) {
855 char fmode[4];
856
857 if (!parsed.fname)
858 return_error(gs_error_undefinedfilename);
859 strcpy(fmode, gp_fmode_wb);
860 if (positionable)
861 strcat(fmode, "+");
862 code = parsed.iodev->procs.fopen(parsed.iodev, parsed.fname, fmode,
863 pfile, NULL, 0);
864 if (code)
865 eprintf1("**** Could not open the file %s .\n", parsed.fname);
866 return code;
867 }
868 *pfile = gp_open_printer((fmt ? pfname : fname), binary);
869 if (*pfile)
870 return 0;
871 eprintf1("**** Could not open the file %s .\n", (fmt ? pfname : fname));
872 return_error(gs_error_invalidfileaccess);
873 }
874
875 /* Close the output file for a device. */
876 int
gx_device_close_output_file(const gx_device * dev,const char * fname,FILE * file)877 gx_device_close_output_file(const gx_device * dev, const char *fname,
878 FILE *file)
879 {
880 gs_parsed_file_name_t parsed;
881 const char *fmt;
882 int code = gx_parse_output_file_name(&parsed, &fmt, fname, strlen(fname));
883
884 if (code < 0)
885 return code;
886 if (parsed.iodev) {
887 if (!strcmp(parsed.iodev->dname, "%stdout%"))
888 return 0;
889 /* NOTE: fname is unsubstituted if the name has any %nnd formats. */
890 if (parsed.iodev != iodev_default)
891 return parsed.iodev->procs.fclose(parsed.iodev, file);
892 }
893 gp_close_printer(file, (parsed.fname ? parsed.fname : fname));
894 return 0;
895 }
896