Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_tlsv12/sys/src/cmd/gs/src/gsdevice.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
    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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
}