changelog shortlog tags branches changeset files revisions annotate raw help

Mercurial > hg > plan9front / sys/src/cmd/gs/src/gsdevice.c

changeset 7253: 986e26228cfe
parent: eaccc3e8d226
author: cinap_lenrek@felloff.net
date: Thu, 23 May 2019 14:59:28 +0200
permissions: -rw-r--r--
description: gs: apply fixes for CVE-2018-16509 (thanks jsmoody)
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
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
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
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 *
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 *
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
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
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
126 gs_copypage(gs_state * pgs)
127 {
128  return gs_output_page(pgs, 1, 0);
129 }
130 int
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
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
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 *
180 gs_currentdevice(const gs_state * pgs)
181 {
182  return pgs->device;
183 }
184 
185 /* Get the name of a device. */
186 const char *
187 gs_devicename(const gx_device * dev)
188 {
189  return dev->dname;
190 }
191 
192 /* Get the initial matrix of a device. */
193 void
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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 ? */
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
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
481 gs_nulldevice(gs_state * pgs)
482 {
483  int code = 0;
484  int saveLockSafety = false;
485 
486  if (pgs->device == 0 || !gx_device_is_null(pgs->device)) {
487  gx_device *ndev;
488  code = gs_copydevice(&ndev, (const gx_device *)&gs_null_device, pgs->memory);
489  if (code < 0)
490  return code;
491  if (gs_currentdevice_inline(pgs) != NULL)
492  saveLockSafety = gs_currentdevice_inline(pgs)->LockSafetyParams;
493 
494  /*
495  * Internal devices have a reference count of 0, not 1,
496  * aside from references from graphics states.
497  */
498  rc_init(ndev, pgs->memory, 0);
499  code = gs_setdevice_no_erase(pgs, ndev);
500  if (code < 0) {
501  gs_free_object(pgs->memory, ndev, "gs_copydevice(device)");
502  return code;
503  }
504  gs_currentdevice_inline(pgs)->LockSafetyParams = saveLockSafety;
505  }
506  return code;
507 }
508 
509 /* Close a device. The client is responsible for ensuring that */
510 /* this device is not current in any graphics state. */
511 int
512 gs_closedevice(gx_device * dev)
513 {
514  int code = 0;
515 
516  if (dev->is_open) {
517  code = (*dev_proc(dev, close_device))(dev);
518  dev->is_open = false;
519  if (code < 0)
520  return_error(code);
521  }
522  return code;
523 }
524 
525 /*
526  * Just set the device without any reinitializing.
527  * (For internal use only.)
528  */
529 void
530 gx_set_device_only(gs_state * pgs, gx_device * dev)
531 {
532  rc_assign(pgs->device, dev, "gx_set_device_only");
533 }
534 
535 /* Compute the size of one scan line for a device, */
536 /* with or without padding to a word boundary. */
537 uint
538 gx_device_raster(const gx_device * dev, bool pad)
539 {
540  ulong bits = (ulong) dev->width * dev->color_info.depth;
541 
542  return (pad ? bitmap_raster(bits) : (uint) ((bits + 7) >> 3));
543 }
544 
545 /* Adjust the resolution for devices that only have a fixed set of */
546 /* geometries, so that the apparent size in inches remains constant. */
547 /* If fit=1, the resolution is adjusted so that the entire image fits; */
548 /* if fit=0, one dimension fits, but the other one is clipped. */
549 int
550 gx_device_adjust_resolution(gx_device * dev,
551  int actual_width, int actual_height, int fit)
552 {
553  double width_ratio = (double)actual_width / dev->width;
554  double height_ratio = (double)actual_height / dev->height;
555  double ratio =
556  (fit ? min(width_ratio, height_ratio) :
557  max(width_ratio, height_ratio));
558 
559  dev->HWResolution[0] *= ratio;
560  dev->HWResolution[1] *= ratio;
561  gx_device_set_width_height(dev, actual_width, actual_height);
562  return 0;
563 }
564 
565 /* Set the HWMargins to values defined in inches. */
566 /* If move_origin is true, also reset the Margins. */
567 /* Note that this assumes a printer-type device (Y axis inverted). */
568 void
569 gx_device_set_margins(gx_device * dev, const float *margins /*[4] */ ,
570  bool move_origin)
571 {
572  int i;
573 
574  for (i = 0; i < 4; ++i)
575  dev->HWMargins[i] = margins[i] * 72.0;
576  if (move_origin) {
577  dev->Margins[0] = -margins[0] * dev->MarginsHWResolution[0];
578  dev->Margins[1] = -margins[3] * dev->MarginsHWResolution[1];
579  }
580 }
581 
582 
583 /* Handle 90 and 270 degree rotation of the Tray
584  * Device must support TrayOrientation in its InitialMatrix and get/put params
585  */
586 private void
587 gx_device_TrayOrientationRotate(gx_device *dev)
588 {
589  if ( dev->TrayOrientation == 90 || dev->TrayOrientation == 270) {
590  /* page sizes don't rotate, height and width do rotate
591  * HWResolution, HWSize, and MediaSize parameters interact,
592  * and must be set before TrayOrientation
593  */
594  int tmp = dev->height;
595  dev->height = dev->width;
596  dev->width = tmp;
597  }
598 }
599 
600 /* Set the width and height, updating MediaSize to remain consistent. */
601 void
602 gx_device_set_width_height(gx_device * dev, int width, int height)
603 {
604  dev->width = width;
605  dev->height = height;
606  dev->MediaSize[0] = width * 72.0 / dev->HWResolution[0];
607  dev->MediaSize[1] = height * 72.0 / dev->HWResolution[1];
608  gx_device_TrayOrientationRotate(dev);
609 }
610 
611 /* Set the resolution, updating width and height to remain consistent. */
612 void
613 gx_device_set_resolution(gx_device * dev, floatp x_dpi, floatp y_dpi)
614 {
615  dev->HWResolution[0] = x_dpi;
616  dev->HWResolution[1] = y_dpi;
617  dev->width = (int)(dev->MediaSize[0] * x_dpi / 72.0 + 0.5);
618  dev->height = (int)(dev->MediaSize[1] * y_dpi / 72.0 + 0.5);
619  gx_device_TrayOrientationRotate(dev);
620 }
621 
622 /* Set the MediaSize, updating width and height to remain consistent. */
623 void
624 gx_device_set_media_size(gx_device * dev, floatp media_width, floatp media_height)
625 {
626  dev->MediaSize[0] = media_width;
627  dev->MediaSize[1] = media_height;
628  dev->width = (int)(media_width * dev->HWResolution[0] / 72.0 + 0.499);
629  dev->height = (int)(media_height * dev->HWResolution[1] / 72.0 + 0.499);
630  gx_device_TrayOrientationRotate(dev);
631 }
632 
633 /*
634  * Copy the color mapping procedures from the target if they are
635  * standard ones (saving a level of procedure call at mapping time).
636  */
637 void
638 gx_device_copy_color_procs(gx_device *dev, const gx_device *target)
639 {
640  dev_proc_map_cmyk_color((*from_cmyk)) =
641  dev_proc(dev, map_cmyk_color);
642  dev_proc_map_rgb_color((*from_rgb)) =
643  dev_proc(dev, map_rgb_color);
644  dev_proc_map_color_rgb((*to_rgb)) =
645  dev_proc(dev, map_color_rgb);
646 
647  /* The logic in this function seems a bit stale; it sets the
648  old-style color procs, but not the new ones
649  (get_color_mapping_procs, get_color_comp_index, encode_color,
650  and decode_color). It should probably copy those as well.
651  */
652  if (from_cmyk == gx_forward_map_cmyk_color ||
653  from_cmyk == cmyk_1bit_map_cmyk_color ||
654  from_cmyk == cmyk_8bit_map_cmyk_color) {
655  from_cmyk = dev_proc(target, map_cmyk_color);
656  set_dev_proc(dev, map_cmyk_color,
657  (from_cmyk == cmyk_1bit_map_cmyk_color ||
658  from_cmyk == cmyk_8bit_map_cmyk_color ?
659  from_cmyk : gx_forward_map_cmyk_color));
660  }
661  if (from_rgb == gx_forward_map_rgb_color ||
662  from_rgb == gx_default_rgb_map_rgb_color) {
663  from_rgb = dev_proc(target, map_rgb_color);
664  set_dev_proc(dev, map_rgb_color,
665  (from_rgb == gx_default_rgb_map_rgb_color ?
666  from_rgb : gx_forward_map_rgb_color));
667  }
668  if (to_rgb == gx_forward_map_color_rgb ||
669  to_rgb == cmyk_1bit_map_color_rgb ||
670  to_rgb == cmyk_8bit_map_color_rgb) {
671  to_rgb = dev_proc(target, map_color_rgb);
672  set_dev_proc(dev, map_color_rgb,
673  (to_rgb == cmyk_1bit_map_color_rgb ||
674  to_rgb == cmyk_8bit_map_color_rgb ?
675  to_rgb : gx_forward_map_color_rgb));
676  }
677 }
678 
679 #define COPY_PARAM(p) dev->p = target->p
680 
681 /*
682  * Copy the color-related device parameters back from the target:
683  * color_info and color mapping procedures.
684  */
685 void
686 gx_device_copy_color_params(gx_device *dev, const gx_device *target)
687 {
688  COPY_PARAM(color_info);
689  COPY_PARAM(cached_colors);
690  gx_device_copy_color_procs(dev, target);
691 }
692 
693 /*
694  * Copy device parameters back from a target. This copies all standard
695  * parameters related to page size and resolution, plus color_info
696  * and (if appropriate) color mapping procedures.
697  */
698 void
699 gx_device_copy_params(gx_device *dev, const gx_device *target)
700 {
701 #define COPY_ARRAY_PARAM(p) memcpy(dev->p, target->p, sizeof(dev->p))
702  COPY_PARAM(width);
703  COPY_PARAM(height);
704  COPY_ARRAY_PARAM(MediaSize);
705  COPY_ARRAY_PARAM(ImagingBBox);
706  COPY_PARAM(ImagingBBox_set);
707  COPY_ARRAY_PARAM(HWResolution);
708  COPY_ARRAY_PARAM(MarginsHWResolution);
709  COPY_ARRAY_PARAM(Margins);
710  COPY_ARRAY_PARAM(HWMargins);
711  COPY_PARAM(PageCount);
712 #undef COPY_ARRAY_PARAM
713  gx_device_copy_color_params(dev, target);
714 }
715 
716 #undef COPY_PARAM
717 
718 /*
719  * Parse the output file name detecting and validating any %nnd format
720  * for inserting the page count. If a format is present, store a pointer
721  * to its last character in *pfmt, otherwise store 0 there.
722  * Note that we assume devices have already been scanned, and any % must
723  * precede a valid format character.
724  *
725  * If there was a format, then return the max_width
726  */
727 private int
728 gx_parse_output_format(gs_parsed_file_name_t *pfn, const char **pfmt)
729 {
730  bool have_format = false, field = 0;
731  int width[2], int_width = sizeof(int) * 3, w = 0;
732  uint i;
733 
734  /* Scan the file name for a format string, and validate it if present. */
735  width[0] = width[1] = 0;
736  for (i = 0; i < pfn->len; ++i)
737  if (pfn->fname[i] == '%') {
738  if (i + 1 < pfn->len && pfn->fname[i + 1] == '%')
739  continue;
740  if (have_format) /* more than one % */
741  return_error(gs_error_undefinedfilename);
742  have_format = true;
743  sw:
744  if (++i == pfn->len)
745  return_error(gs_error_undefinedfilename);
746  switch (pfn->fname[i]) {
747  case 'l':
748  int_width = sizeof(long) * 3;
749  case ' ': case '#': case '+': case '-':
750  goto sw;
751  case '.':
752  if (field)
753  return_error(gs_error_undefinedfilename);
754  field = 1;
755  continue;
756  case '0': case '1': case '2': case '3': case '4':
757  case '5': case '6': case '7': case '8': case '9':
758  width[field] = width[field] * 10 + pfn->fname[i] - '0';
759  goto sw;
760  case 'd': case 'i': case 'u': case 'o': case 'x': case 'X':
761  *pfmt = &pfn->fname[i];
762  continue;
763  default:
764  return_error(gs_error_undefinedfilename);
765  }
766  }
767  if (have_format) {
768  /* Calculate a conservative maximum width. */
769  w = max(width[0], width[1]);
770  w = max(w, int_width) + 5;
771  }
772  return w;
773 }
774 
775 /*
776  * Parse the output file name for a device, recognizing "-" and "|command",
777  * and also detecting and validating any %nnd format for inserting the
778  * page count. If a format is present, store a pointer to its last
779  * character in *pfmt, otherwise store 0 there. Note that an empty name
780  * is currently allowed.
781  */
782 int
783 gx_parse_output_file_name(gs_parsed_file_name_t *pfn, const char **pfmt,
784  const char *fname, uint fnlen)
785 {
786  int code;
787 
788  *pfmt = 0;
789  pfn->memory = 0;
790  pfn->iodev = NULL;
791  pfn->fname = NULL; /* irrelevant since length = 0 */
792  pfn->len = 0;
793  if (fnlen == 0) /* allow null name */
794  return 0;
795  /*
796  * If the file name begins with a %, it might be either an IODevice
797  * or a %nnd format. Check (carefully) for this case.
798  */
799  code = gs_parse_file_name(pfn, fname, fnlen);
800  if (code < 0) {
801  if (fname[0] == '%') {
802  /* not a recognized iodev -- may be a leading format descriptor */
803  pfn->len = fnlen;
804  pfn->fname = fname;
805  code = gx_parse_output_format(pfn, pfmt);
806  }
807  if (code < 0)
808  return code;
809  }
810  if (!pfn->iodev) {
811  if ( (pfn->len == 1) && (pfn->fname[0] == '-') ) {
812  pfn->iodev = gs_findiodevice((const byte *)"%stdout", 7);
813  pfn->fname = NULL;
814  } else if (pfn->fname[0] == '|') {
815  pfn->iodev = gs_findiodevice((const byte *)"%pipe", 5);
816  pfn->fname++, pfn->len--;
817  } else
818  pfn->iodev = iodev_default;
819  if (!pfn->iodev)
820  return_error(gs_error_undefinedfilename);
821  }
822  if (!pfn->fname)
823  return 0;
824  code = gx_parse_output_format(pfn, pfmt);
825  if (code < 0)
826  return code;
827  if (strlen(pfn->iodev->dname) + pfn->len + code >= gp_file_name_sizeof)
828  return_error(gs_error_undefinedfilename);
829  return 0;
830 }
831 
832 /* Open the output file for a device. */
833 int
834 gx_device_open_output_file(const gx_device * dev, char *fname,
835  bool binary, bool positionable, FILE ** pfile)
836 {
837  gs_parsed_file_name_t parsed;
838  const char *fmt;
839  char pfname[gp_file_name_sizeof];
840  int code = gx_parse_output_file_name(&parsed, &fmt, fname, strlen(fname));
841 
842  if (code < 0)
843  return code;
844  if (parsed.iodev && !strcmp(parsed.iodev->dname, "%stdout%")) {
845  if (parsed.fname)
846  return_error(gs_error_undefinedfilename);
847  *pfile = dev->memory->gs_lib_ctx->fstdout;
848  /* Force stdout to binary. */
849  return gp_setmode_binary(*pfile, true);
850  }
851  if (fmt) {
852  long count1 = dev->PageCount + 1;
853 
854  while (*fmt != 'l' && *fmt != '%')
855  --fmt;
856  if (*fmt == 'l')
857  sprintf(pfname, parsed.fname, count1);
858  else
859  sprintf(pfname, parsed.fname, (int)count1);
860  parsed.fname = pfname;
861  parsed.len = strlen(parsed.fname);
862  }
863  if (positionable || (parsed.iodev && parsed.iodev != iodev_default)) {
864  char fmode[4];
865 
866  if (!parsed.fname)
867  return_error(gs_error_undefinedfilename);
868  strcpy(fmode, gp_fmode_wb);
869  if (positionable)
870  strcat(fmode, "+");
871  code = parsed.iodev->procs.fopen(parsed.iodev, parsed.fname, fmode,
872  pfile, NULL, 0);
873  if (code)
874  eprintf1("**** Could not open the file %s .\n", parsed.fname);
875  return code;
876  }
877  *pfile = gp_open_printer((fmt ? pfname : fname), binary);
878  if (*pfile)
879  return 0;
880  eprintf1("**** Could not open the file %s .\n", (fmt ? pfname : fname));
881  return_error(gs_error_invalidfileaccess);
882 }
883 
884 /* Close the output file for a device. */
885 int
886 gx_device_close_output_file(const gx_device * dev, const char *fname,
887  FILE *file)
888 {
889  gs_parsed_file_name_t parsed;
890  const char *fmt;
891  int code = gx_parse_output_file_name(&parsed, &fmt, fname, strlen(fname));
892 
893  if (code < 0)
894  return code;
895  if (parsed.iodev) {
896  if (!strcmp(parsed.iodev->dname, "%stdout%"))
897  return 0;
898  /* NOTE: fname is unsubstituted if the name has any %nnd formats. */
899  if (parsed.iodev != iodev_default)
900  return parsed.iodev->procs.fclose(parsed.iodev, file);
901  }
902  gp_close_printer(file, (parsed.fname ? parsed.fname : fname));
903  return 0;
904 }