Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/base/gdevprn.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2024 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* Generic printer driver support */
18
#include "ctype_.h"
19
#include "gdevprn.h"
20
#include "gp.h"
21
#include "gdevdevn.h"           /* for gs_devn_params_s */
22
#include "gsdevice.h"   /* for gs_deviceinitialmatrix */
23
#include "gxdevsop.h"   /* for gxdso_* */
24
#include "gsfname.h"
25
#include "gsparam.h"
26
#include "gxclio.h"
27
#include "gxgetbit.h"
28
#include "gdevplnx.h"
29
#include "gstrans.h"
30
#include "gxdownscale.h"
31
#include "gsbitops.h"
32
33
#include "gdevkrnlsclass.h" /* 'standard' built in subclasses, currently First/Last Page and obejct filter */
34
35
/*#define DEBUGGING_HACKS*/
36
37
/* GC information */
38
static
39
10.3M
ENUM_PTRS_WITH(device_printer_enum_ptrs, gx_device_printer *pdev);
40
9.90M
    ENUM_PREFIX(st_device_clist_mutatable, 2);
41
0
    break;
42
202k
case 0:ENUM_RETURN(gx_device_enum_ptr(pdev->parent));
43
202k
case 1:ENUM_RETURN(gx_device_enum_ptr(pdev->child));
44
10.3M
ENUM_PTRS_END
45
static
46
202k
RELOC_PTRS_WITH(device_printer_reloc_ptrs, gx_device_printer *pdev)
47
202k
{
48
202k
    pdev->parent = gx_device_reloc_ptr(pdev->parent, gcst);
49
202k
    pdev->child = gx_device_reloc_ptr(pdev->child, gcst);
50
202k
    RELOC_PREFIX(st_device_clist_mutatable);
51
202k
} RELOC_PTRS_END
52
public_st_device_printer();
53
54
/* ---------------- Standard device procedures ---------------- */
55
56
/* Forward references */
57
int gdev_prn_maybe_realloc_memory(gx_device_printer *pdev,
58
                                  gdev_space_params *old_space,
59
                                  int old_width, int old_height,
60
                                  bool old_page_uses_transparency);
61
62
static int
63
gdev_prn_output_page_aux(gx_device * pdev, int num_copies, int flush, bool seekable, bool bg_print_ok);
64
65
extern dev_proc_open_device(pattern_clist_open_device);
66
extern dev_proc_open_device(clist_open);
67
extern dev_proc_close_device(clist_close);
68
69
/* The function run in a background thread */
70
static void prn_print_page_in_background(void *data);
71
72
/* wait for a background thread to finish and clean up background printing */
73
static void prn_finish_bg_print(gx_device_printer *ppdev);
74
75
/* ------ Open/close ------ */
76
/* Open a generic printer device. */
77
/* Specific devices may wish to extend this. */
78
int
79
gdev_prn_open(gx_device * pdev)
80
120k
{
81
120k
    gx_device_printer * ppdev;
82
120k
    int code;
83
120k
    bool update_procs = false;
84
85
120k
    code = install_internal_subclass_devices(&pdev, &update_procs);
86
120k
    if (code < 0)
87
0
        return code;
88
89
120k
    ppdev = (gx_device_printer *)pdev;
90
91
120k
    ppdev->file = NULL;
92
120k
    code = gdev_prn_allocate_memory(pdev, NULL, 0, 0);
93
120k
    if (update_procs) {
94
0
        if (pdev->ObjectHandlerPushed) {
95
0
            gx_copy_device_procs(pdev->parent, pdev, &gs_obj_filter_device);
96
0
            pdev = pdev->parent;
97
0
        }
98
0
        if (pdev->PageHandlerPushed) {
99
0
            gx_copy_device_procs(pdev->parent, pdev, &gs_flp_device);
100
0
            pdev = pdev->parent;
101
0
        }
102
0
        if (pdev->NupHandlerPushed)
103
0
            gx_copy_device_procs(pdev->parent, pdev, &gs_nup_device);
104
0
    }
105
120k
    if (code < 0)
106
0
        return code;
107
120k
    if (ppdev->OpenOutputFile)
108
0
        code = gdev_prn_open_printer(pdev, 1);
109
120k
    return code;
110
120k
}
111
112
/* This is called various places to wait for any pending bg print thread and */
113
/* perform its cleanup                                                       */
114
static void
115
prn_finish_bg_print(gx_device_printer *ppdev)
116
446k
{
117
    /* if we have a a bg printing device that was created, then wait for its  */
118
    /* semaphore (it may already have been signalled, but that's OK.) then  */
119
    /* close and unlink the files and free the device and its private allocator */
120
446k
    if (ppdev->bg_print && (ppdev->bg_print->device != NULL)) {
121
0
        int closecode;
122
0
        gx_device_printer *bgppdev = (gx_device_printer *)ppdev->bg_print->device;
123
124
0
        gx_semaphore_wait(ppdev->bg_print->sema);
125
        /* If numcopies > 1, then the bg_print->device will have closed and reopened
126
         * the output file, so the pointer in the original device is now stale,
127
         * so copy it back.
128
         * If numcopies == 1, this is pointless, but benign.
129
         */
130
0
        ppdev->file = bgppdev->file;
131
0
        closecode = gdev_prn_close_printer((gx_device *)ppdev);
132
0
        if (ppdev->bg_print->return_code == 0)
133
0
            ppdev->bg_print->return_code = closecode; /* return code here iff there wasn't another error */
134
0
        teardown_device_and_mem_for_thread(ppdev->bg_print->device,
135
0
                                           ppdev->bg_print->thread_id, true);
136
0
        ppdev->bg_print->device = NULL;
137
0
        if (ppdev->bg_print->ocfile) {
138
0
            closecode = ppdev->bg_print->oio_procs->fclose(ppdev->bg_print->ocfile, ppdev->bg_print->ocfname, true);
139
0
            if (ppdev->bg_print->return_code == 0)
140
0
               ppdev->bg_print->return_code = closecode;
141
0
        }
142
0
        if (ppdev->bg_print->ocfname) {
143
0
            gs_free_object(ppdev->memory->non_gc_memory, ppdev->bg_print->ocfname, "prn_finish_bg_print(ocfname)");
144
0
        }
145
0
        if (ppdev->bg_print->obfile) {
146
0
            closecode = ppdev->bg_print->oio_procs->fclose(ppdev->bg_print->obfile, ppdev->bg_print->obfname, true);
147
0
            if (ppdev->bg_print->return_code == 0)
148
0
               ppdev->bg_print->return_code = closecode;
149
0
        }
150
0
        if (ppdev->bg_print->obfname) {
151
0
            gs_free_object(ppdev->memory->non_gc_memory, ppdev->bg_print->obfname, "prn_finish_bg_print(obfname)");
152
0
        }
153
0
        ppdev->bg_print->ocfile = ppdev->bg_print->obfile =
154
0
          ppdev->bg_print->ocfname = ppdev->bg_print->obfname = NULL;
155
0
    }
156
446k
}
157
/* Generic closing for the printer device. */
158
/* Specific devices may wish to extend this. */
159
int
160
gdev_prn_close(gx_device * pdev)
161
120k
{
162
120k
    gx_device_printer * const ppdev = (gx_device_printer *)pdev;
163
120k
    int code = 0;
164
165
120k
    prn_finish_bg_print(ppdev);
166
120k
    if (ppdev->bg_print != NULL && ppdev->bg_print->sema != NULL) {
167
0
        gx_semaphore_free(ppdev->bg_print->sema);
168
0
        ppdev->bg_print->sema = NULL;   /* prevent double free */
169
0
    }
170
120k
    gdev_prn_free_memory(pdev);
171
120k
    if (ppdev->file != NULL) {
172
44.7k
        code = gx_device_close_output_file(pdev, ppdev->fname, ppdev->file);
173
44.7k
        ppdev->file = NULL;
174
44.7k
    }
175
120k
    return code;
176
120k
}
177
178
int
179
gdev_prn_forwarding_dev_spec_op(gx_device *pdev, int dev_spec_op, void *data, int size)
180
160M
{
181
160M
    gx_device_printer *ppdev = (gx_device_printer *)pdev;
182
160M
    int code;
183
184
    /* if the device is a printer device, we will get here, but allow for a printer device */
185
    /* that has a non-default dev_spec_op that may want to not support saved_pages, if so  */
186
    /* that device can return an error from the supports_saved_pages spec_op.              */
187
160M
    code = ppdev->orig_procs.dev_spec_op(pdev, dev_spec_op, data, size);
188
160M
    if (dev_spec_op == gxdso_supports_saved_pages)  /* printer devices support saved pages */
189
932k
        return code == 0 ? 1: code;  /*default returns 0, but we still want saved-page support */
190
159M
    return code;
191
160M
}
192
193
int
194
gdev_prn_dev_spec_op(gx_device *pdev, int dev_spec_op, void *data, int size)
195
98.6M
{
196
98.6M
    if (dev_spec_op == gxdso_supports_saved_pages)
197
1.21M
        return 1;
198
199
97.4M
    if (dev_spec_op == gxdso_get_dev_param) {
200
2.51M
        int code;
201
2.51M
        dev_param_req_t *request = (dev_param_req_t *)data;
202
203
2.51M
        code = gdev_prn_get_param(pdev, request->Param, request->list);
204
2.51M
        if (code != gs_error_undefined)
205
172k
            return code;
206
2.51M
    }
207
208
#ifdef DEBUG
209
    if (dev_spec_op == gxdso_debug_printer_check)
210
        return 1;
211
#endif
212
213
97.3M
    return gx_default_dev_spec_op(pdev, dev_spec_op, data, size);
214
97.4M
}
215
216
static bool /* ret true if device was cmd list, else false */
217
gdev_prn_tear_down(gx_device *pdev, byte **the_memory)
218
250k
{
219
250k
    gx_device_printer * const ppdev = (gx_device_printer *)pdev;
220
250k
    gx_device_memory * const pmemdev = (gx_device_memory *)pdev;
221
250k
    gx_device_clist *const pclist_dev = (gx_device_clist *)pdev;
222
250k
    gx_device_clist_common * const pcldev = &pclist_dev->common;
223
250k
    gx_device_clist_reader * const pcrdev = &pclist_dev->reader;
224
250k
    bool was_command_list;
225
226
250k
    if (PRINTER_IS_CLIST(ppdev)) {
227
        /* Close cmd list device & point to the storage */
228
250k
        clist_close( (gx_device *)pcldev );
229
250k
        *the_memory = ppdev->buf;
230
250k
        ppdev->buf = 0;
231
250k
        ppdev->buffer_space = 0;
232
250k
        pmemdev->base = 0;    /* in case finalize tries to free this */
233
250k
        was_command_list = true;
234
235
250k
        prn_finish_bg_print(ppdev);
236
237
250k
        gs_free_object(pcldev->memory->non_gc_memory, pcldev->cache_chunk, "free tile cache for clist");
238
250k
        pcldev->cache_chunk = 0;
239
240
250k
        rc_decrement(pcldev->icc_cache_cl, "gdev_prn_tear_down");
241
250k
        pcldev->icc_cache_cl = NULL;
242
243
250k
        clist_free_icc_table(pcldev->icc_table, pcldev->memory);
244
250k
        pcldev->icc_table = NULL;
245
246
        /* If the clist is a reader clist, free any color_usage_array
247
         * memory used by same.
248
         */
249
250k
        if (!CLIST_IS_WRITER(pclist_dev))
250
6.17k
            gs_free_object(pcrdev->memory, pcrdev->color_usage_array, "clist_color_usage_array");
251
252
250k
    } else {
253
        /* point at the device bitmap, no need to close mem dev */
254
0
        *the_memory = pmemdev->base;
255
0
        pmemdev->base = 0;
256
0
        was_command_list = false;
257
0
    }
258
259
    /* Reset device proc vector to default */
260
250k
    if (ppdev->orig_procs.open_device != NULL)
261
250k
        pdev->procs = ppdev->orig_procs;
262
250k
    ppdev->orig_procs.open_device = NULL; /* prevent uninit'd restore of procs */
263
264
250k
    return was_command_list;
265
250k
}
266
267
static int
268
gdev_prn_allocate(gx_device *pdev, gdev_space_params *new_space_params,
269
                  int new_width, int new_height, bool reallocate)
270
250k
{
271
250k
    gx_device_printer * const ppdev = (gx_device_printer *)pdev;
272
250k
    gx_device_memory * const pmemdev = (gx_device_memory *)pdev;
273
250k
    byte *the_memory = 0;
274
250k
    gdev_space_params save_params = ppdev->space_params;
275
250k
    int save_width = 0x0badf00d; /* Quiet compiler */
276
250k
    int save_height = 0x0badf00d; /* Quiet compiler */
277
250k
    bool is_command_list = false; /* Quiet compiler */
278
250k
    bool save_is_command_list = false; /* Quiet compiler */
279
250k
    bool size_ok = 0;
280
250k
    int ecode = 0;
281
250k
    int code;
282
250k
    int pass;
283
250k
    gs_memory_t *buffer_memory =
284
250k
        (ppdev->buffer_memory == 0 ? pdev->memory->non_gc_memory :
285
250k
         ppdev->buffer_memory);
286
250k
    bool deep = device_is_deep(pdev);
287
288
    /* If reallocate, find allocated memory & tear down buffer device */
289
250k
    if (reallocate)
290
130k
        save_is_command_list = gdev_prn_tear_down(pdev, &the_memory);
291
292
293
    /* bg_print allocation is not fatal, we just continue (as far as possible) without BGPrint */
294
250k
    if (ppdev->bg_print == NULL)
295
120k
        ppdev->bg_print = (bg_print_t *)gs_alloc_bytes(pdev->memory->non_gc_memory, sizeof(bg_print_t), "prn bg_print");
296
250k
    if (ppdev->bg_print == NULL) {
297
0
        emprintf(pdev->memory, "Failed to allocate memory for BGPrint, attempting to continue without BGPrint\n");
298
250k
    } else {
299
250k
        memset(ppdev->bg_print, 0, sizeof(bg_print_t));
300
250k
    }
301
302
    /* Re/allocate memory */
303
250k
    ppdev->orig_procs = pdev->procs;
304
250k
    for ( pass = 1; pass <= (reallocate ? 2 : 1); ++pass ) {
305
250k
        size_t mem_space;
306
250k
        size_t pdf14_trans_buffer_size = 0;
307
250k
        byte *base = 0;
308
250k
        bool bufferSpace_is_default = false;
309
250k
        gdev_space_params space_params;
310
250k
        gx_device_buf_space_t buf_space;
311
312
250k
        if (reallocate)
313
130k
            switch (pass)
314
130k
                {
315
130k
                case 1:
316
                    /* Setup device to get reallocated */
317
130k
                    ppdev->space_params = *new_space_params;
318
130k
                    save_width = ppdev->width;
319
130k
                    ppdev->width = new_width;
320
130k
                    save_height = ppdev->height;
321
130k
                    ppdev->height = new_height;
322
130k
                    break;
323
0
                case 2: /* only comes here if reallocate */
324
                    /* Restore device to previous contents */
325
0
                    ppdev->space_params = save_params;
326
0
                    ppdev->width = save_width;
327
0
                    ppdev->height = save_height;
328
0
                    break;
329
130k
                }
330
331
        /* Init clist/mem device-specific fields */
332
250k
        memset(ppdev->skip, 0, sizeof(ppdev->skip));
333
250k
        size_ok = ppdev->printer_procs.buf_procs.size_buf_device
334
250k
            (&buf_space, pdev, NULL, pdev->height, false) >= 0;
335
336
        /* Make sure we won't overflow a size_t, if we do then we'll use a clist below */
337
250k
        if (ARCH_MAX_SIZE_T - buf_space.bits < buf_space.line_ptrs)
338
0
            size_ok = 0;
339
340
250k
        mem_space = buf_space.bits + buf_space.line_ptrs;
341
250k
        if (ppdev->page_uses_transparency) {
342
20.6k
            pdf14_trans_buffer_size = (ESTIMATED_PDF14_ROW_SPACE(max(1, pdev->width), pdev->color_info.num_components, deep ? 16 : 8) >> 3);
343
20.6k
            if (new_height < (max_size_t - mem_space) / pdf14_trans_buffer_size) {
344
20.6k
                pdf14_trans_buffer_size *= pdev->height;
345
20.6k
            } else {
346
0
                size_ok = 0;
347
0
            }
348
20.6k
        }
349
350
        /* Compute desired space params: never use the space_params as-is. */
351
        /* Rather, give the dev-specific driver a chance to adjust them. */
352
250k
        space_params = ppdev->space_params;
353
250k
        space_params.BufferSpace = 0;
354
250k
        (*ppdev->printer_procs.get_space_params)(ppdev, &space_params);
355
250k
        if (space_params.BufferSpace == 0) {
356
250k
            if (space_params.band.BandBufferSpace > 0)
357
0
                space_params.BufferSpace = space_params.band.BandBufferSpace;
358
250k
            else {
359
250k
                space_params.BufferSpace = ppdev->space_params.BufferSpace;
360
250k
                bufferSpace_is_default = true;
361
250k
            }
362
250k
        }
363
364
        /* Determine if we can use a full bitmap buffer, or have to use banding */
365
250k
        if (pass > 1)
366
0
            is_command_list = save_is_command_list;
367
250k
        else {
368
250k
            is_command_list = space_params.banding_type == BandingAlways ||
369
250k
                ppdev->saved_pages_list != NULL ||
370
250k
                mem_space + pdf14_trans_buffer_size >= space_params.MaxBitmap ||
371
250k
                !size_ok;     /* too big to allocate */
372
250k
        }
373
250k
        if (!is_command_list) {
374
0
            byte *trans_buffer_reserve_space = NULL;
375
376
            /* Try to allocate memory for full memory buffer, then allocate the
377
               pdf14_trans_buffer_size to make sure we have enough space for that */
378
            /* NOTE: Assumes that caller won't normally call this function if page
379
               size didn't actually change, so we can free/alloc without checking
380
               that the new size is different than old size.
381
            */
382
0
            if (reallocate) {
383
0
                gs_free_object(buffer_memory, the_memory, "printer_buffer");
384
0
                the_memory = NULL;
385
0
            }
386
0
            base = gs_alloc_bytes(buffer_memory, mem_space, "printer_buffer");
387
0
            if (base == 0)
388
0
                is_command_list = true;
389
0
            else
390
0
                the_memory = base;
391
0
            trans_buffer_reserve_space = gs_alloc_bytes(buffer_memory, (uint)pdf14_trans_buffer_size,
392
0
                                                        "pdf14_trans_buffer_reserve test");
393
0
            if (trans_buffer_reserve_space == NULL) {
394
                /* the pdf14 reserve test failed, switch to clist mode, the 'base' memory freed below */
395
0
                is_command_list = true;
396
0
            } else {
397
0
                gs_free_object(buffer_memory, trans_buffer_reserve_space, "pdf14_trans_buffer_reserve OK");
398
0
            }
399
0
        }
400
250k
        if (!is_command_list && pass == 1 && PRN_MIN_MEMORY_LEFT != 0
401
250k
            && buffer_memory == pdev->memory->non_gc_memory) {
402
            /* before using full memory buffer, ensure enough working mem left */
403
0
            byte * left = gs_alloc_bytes( buffer_memory,
404
0
                                          PRN_MIN_MEMORY_LEFT, "printer mem left");
405
0
            if (left == 0)
406
0
                is_command_list = true;
407
0
            else
408
0
                gs_free_object(buffer_memory, left, "printer mem left");
409
0
        }
410
411
250k
        if (is_command_list) {
412
            /* Buffer the image in a command list. */
413
            /* Release the buffer if we allocated it. */
414
250k
            int code;
415
250k
            gx_device_printer * const ppdev = (gx_device_printer *)pdev;
416
417
250k
            if (!reallocate) {
418
120k
                gs_free_object(buffer_memory, the_memory,
419
120k
                               "printer buffer(open)");
420
120k
                the_memory = 0;
421
120k
            }
422
250k
            if (space_params.banding_type == BandingNever) {
423
0
                ecode = gs_note_error(gs_error_VMerror);
424
0
                continue;
425
0
            }
426
250k
            if (ppdev->bg_print) {
427
250k
                ppdev->bg_print->ocfname = ppdev->bg_print->obfname =
428
250k
                    ppdev->bg_print->obfile = ppdev->bg_print->ocfile = NULL;
429
250k
            }
430
431
250k
            code = clist_mutate_to_clist((gx_device_clist_mutatable *)pdev,
432
250k
                                         buffer_memory,
433
250k
                                         &the_memory, &space_params,
434
250k
                                         !bufferSpace_is_default,
435
250k
                                         &ppdev->printer_procs.buf_procs,
436
250k
                                         gdev_prn_forwarding_dev_spec_op,
437
250k
                                         PRN_MIN_BUFFER_SPACE);
438
250k
            if (ecode == 0)
439
250k
                ecode = code;
440
441
250k
            if (code >= 0 || (reallocate && pass > 1)) {
442
250k
                ppdev->initialize_device_procs = clist_initialize_device_procs;
443
                /* Hacky - we know this can't fail. */
444
250k
                (void)ppdev->initialize_device_procs((gx_device *)ppdev);
445
250k
                gx_device_fill_in_procs((gx_device *)ppdev);
446
250k
            }
447
250k
        } else {
448
            /* Render entirely in memory. */
449
0
            gx_device *bdev = (gx_device *)pmemdev;
450
0
            int code;
451
452
0
            ppdev->buffer_space = 0;
453
0
            if ((code = gdev_create_buf_device
454
0
                 (ppdev->printer_procs.buf_procs.create_buf_device,
455
0
                  &bdev, pdev, 0, NULL, NULL, NULL)) < 0 ||
456
0
                (code = ppdev->printer_procs.buf_procs.setup_buf_device
457
0
                 (bdev, base, buf_space.raster,
458
0
                  (byte **)(base + buf_space.bits), 0, pdev->height,
459
0
                  pdev->height)) < 0
460
0
                ) {
461
                /* Catastrophic. Shouldn't ever happen */
462
0
                gs_free_object(buffer_memory, base, "printer buffer");
463
0
                pdev->procs = ppdev->orig_procs;
464
0
                ppdev->orig_procs.open_device = 0;  /* prevent uninit'd restore of procs */
465
0
                gs_free_object(pdev->memory->non_gc_memory, ppdev->bg_print, "prn bg_print");
466
0
                ppdev->bg_print = NULL;
467
0
                return_error(code);
468
0
            }
469
0
        }
470
250k
        if (ecode == 0)
471
250k
            break;
472
250k
    }
473
474
250k
    if (ecode >= 0 || reallocate) { /* even if realloc failed */
475
        /* Synthesize the procedure vector. */
476
        /* Rendering operations come from the memory or clist device, */
477
        /* non-rendering come from the printer device. */
478
4.01M
#define COPY_PROC(p) set_dev_proc(ppdev, p, ppdev->orig_procs.p)
479
250k
        COPY_PROC(get_initial_matrix);
480
250k
        COPY_PROC(output_page);
481
250k
        COPY_PROC(close_device);
482
250k
        COPY_PROC(map_rgb_color);
483
250k
        COPY_PROC(map_color_rgb);
484
250k
        COPY_PROC(get_params);
485
250k
        COPY_PROC(put_params);
486
250k
        COPY_PROC(map_cmyk_color);
487
        /* All printers are page devices, even if they didn't use the */
488
        /* standard macros for generating their procedure vectors. */
489
250k
        set_dev_proc(ppdev, get_page_device, gx_page_device_get_page_device);
490
250k
        COPY_PROC(get_clipping_box);
491
250k
        COPY_PROC(get_hardware_params);
492
250k
        COPY_PROC(get_color_mapping_procs);
493
250k
        COPY_PROC(get_color_comp_index);
494
250k
        COPY_PROC(encode_color);
495
250k
        COPY_PROC(decode_color);
496
250k
        COPY_PROC(update_spot_equivalent_colors);
497
250k
        COPY_PROC(ret_devn_params);
498
        /* This can be set from the memory device (planar) or target */
499
250k
        if ( dev_proc(ppdev, put_image) == gx_default_put_image )
500
250k
            set_dev_proc(ppdev, put_image, ppdev->orig_procs.put_image);
501
250k
#undef COPY_PROC
502
        /* If using a command list, already opened the device. */
503
250k
        if (is_command_list)
504
250k
            code = ecode;
505
0
        else
506
            /* If this open_device fails, do we need to free everything? */
507
0
            code = (*dev_proc(pdev, open_device))(pdev);
508
250k
    } else {
509
0
        pdev->procs = ppdev->orig_procs;
510
0
        ppdev->orig_procs.open_device = 0;  /* prevent uninit'd restore of procs */
511
0
        code = ecode;
512
0
    }
513
250k
    if (code < 0) {
514
0
          gs_free_object(pdev->memory->non_gc_memory, ppdev->bg_print, "prn bg_print");
515
0
          ppdev->bg_print = NULL;
516
0
    }
517
250k
    return code;
518
250k
}
519
520
int
521
gdev_prn_allocate_memory(gx_device *pdev,
522
                         gdev_space_params *new_space_params,
523
                         int new_width, int new_height)
524
120k
{
525
120k
    return gdev_prn_allocate(pdev, new_space_params,
526
120k
                             new_width, new_height, false);
527
120k
}
528
529
int
530
gdev_prn_reallocate_memory(gx_device *pdev,
531
                         gdev_space_params *new_space_params,
532
                         int new_width, int new_height)
533
130k
{
534
130k
    return gdev_prn_allocate(pdev, new_space_params,
535
130k
                             new_width, new_height, true);
536
130k
}
537
538
int
539
gdev_prn_free_memory(gx_device *pdev)
540
120k
{
541
120k
    gx_device_printer * const ppdev = (gx_device_printer *)pdev;
542
120k
    byte *the_memory = 0;
543
120k
    gs_memory_t *buffer_memory =
544
120k
        (ppdev->buffer_memory == 0 ? pdev->memory->non_gc_memory :
545
120k
         ppdev->buffer_memory);
546
547
120k
    gdev_prn_tear_down(pdev, &the_memory);
548
120k
    gs_free_object(pdev->memory->non_gc_memory, ppdev->bg_print, "gdev_prn_free_memory");
549
120k
    ppdev->bg_print = NULL;
550
120k
    gs_free_object(buffer_memory, the_memory, "gdev_prn_free_memory");
551
120k
    return 0;
552
120k
}
553
554
/* for saved pages, we need to make sure and free up the saved_pages_list */
555
void
556
gdev_prn_finalize(gx_device *pdev)
557
0
{
558
0
    gx_device_printer * const ppdev = (gx_device_printer *)pdev;
559
560
0
    if (ppdev->saved_pages_list != NULL) {
561
0
        gx_saved_pages_list_free(ppdev->saved_pages_list);
562
0
        ppdev->saved_pages_list = NULL;
563
0
    }
564
0
}
565
566
567
/* ------ Get/put parameters ------ */
568
569
int
570
gdev_prn_get_param(gx_device *dev, char *Param, void *list)
571
2.51M
{
572
2.51M
    gx_device_printer * const ppdev = (gx_device_printer *)dev;
573
2.51M
    gs_param_list * plist = (gs_param_list *)list;
574
2.51M
    bool pageneutralcolor = false;
575
576
2.51M
    if (strcmp(Param, "Duplex") == 0) {
577
0
        if (ppdev->Duplex_set >= 0) {
578
0
            if (ppdev->Duplex_set)
579
0
                return param_write_bool(plist, "Duplex", &ppdev->Duplex);
580
0
            else
581
0
                return param_write_null(plist, "Duplex");
582
0
        }
583
0
    }
584
2.51M
    if (strcmp(Param, "NumRenderingThreads") == 0) {
585
0
        return param_write_int(plist, "NumRenderingThreads", &ppdev->num_render_threads_requested);
586
0
    }
587
2.51M
    if (strcmp(Param, "OpenOutputFile") == 0) {
588
0
        return param_write_bool(plist, "OpenOutputFile", &ppdev->OpenOutputFile);
589
0
    }
590
2.51M
    if (strcmp(Param, "BGPrint") == 0) {
591
57.5k
        return param_write_bool(plist, "BGPrint", &ppdev->bg_print_requested);
592
57.5k
    }
593
2.45M
    if (strcmp(Param, "ReopenPerPage") == 0) {
594
0
        return param_write_bool(plist, "ReopenPerPage", &ppdev->ReopenPerPage);
595
0
    }
596
2.45M
    if (strcmp(Param, "BandListStorage") == 0) {
597
0
        gs_param_string bls;
598
0
        gs_lib_ctx_core_t *core = dev->memory->gs_lib_ctx->core;
599
        /* Force the default to 'memory' if clist file I/O is not included in this build */
600
0
        if (core->clist_io_procs_file == NULL)
601
0
            ppdev->BLS_force_memory = true;
602
0
        if (ppdev->BLS_force_memory) {
603
0
            bls.data = (byte *)"memory";
604
0
            bls.size = 6;
605
0
            bls.persistent = false;
606
0
        } else {
607
0
            bls.data = (byte *)"file";
608
0
            bls.size = 4;
609
0
            bls.persistent = false;
610
0
        }
611
0
        return param_write_string(plist, "BandListStorage", &bls);
612
0
    }
613
2.45M
    if (strcmp(Param, "OutputFile") == 0) {
614
0
        gs_param_string ofns;
615
616
0
        ofns.data = (const byte *)ppdev->fname,
617
0
        ofns.size = strlen(ppdev->fname),
618
0
        ofns.persistent = false;
619
0
        return param_write_string(plist, "OutputFile", &ofns);
620
0
    }
621
2.45M
    if (strcmp(Param, "saved-pages") == 0) {
622
0
        gs_param_string saved_pages;
623
        /* Always return an empty string for saved-pages */
624
0
        saved_pages.data = (const byte *)"";
625
0
        saved_pages.size = 0;
626
0
        saved_pages.persistent = false;
627
0
        return param_write_string(plist, "saved-pages", &saved_pages);
628
0
    }
629
2.45M
    if (dev->icc_struct != NULL)
630
2.45M
        pageneutralcolor = dev->icc_struct->pageneutralcolor;
631
2.45M
    if (strcmp(Param, "pageneutralcolor") == 0) {
632
0
        return param_write_bool(plist, "pageneutralcolor", &pageneutralcolor);
633
0
    }
634
2.45M
    return gx_default_get_param(dev, Param, list);
635
2.45M
}
636
637
/* Get parameters.  Printer devices add several more parameters */
638
/* to the default set. */
639
int
640
gdev_prn_get_params(gx_device * pdev, gs_param_list * plist)
641
2.57M
{
642
2.57M
    gx_device_printer * const ppdev = (gx_device_printer *)pdev;
643
2.57M
    int code = gx_default_get_params(pdev, plist);
644
2.57M
    gs_param_string ofns;
645
2.57M
    gs_param_string bls;
646
2.57M
    gs_param_string saved_pages;
647
2.57M
    bool pageneutralcolor = false;
648
2.57M
    gs_lib_ctx_core_t *core = pdev->memory->gs_lib_ctx->core;
649
650
2.57M
    if (pdev->icc_struct != NULL)
651
2.47M
        pageneutralcolor = pdev->icc_struct->pageneutralcolor;
652
2.57M
    if (code < 0 ||
653
2.57M
        (ppdev->Duplex_set >= 0 &&
654
2.57M
        (code = (ppdev->Duplex_set ?
655
0
                  param_write_bool(plist, "Duplex", &ppdev->Duplex) :
656
0
                  param_write_null(plist, "Duplex"))) < 0) ||
657
2.57M
        (code = param_write_int(plist, "NumRenderingThreads", &ppdev->num_render_threads_requested)) < 0 ||
658
2.57M
        (code = param_write_bool(plist, "OpenOutputFile", &ppdev->OpenOutputFile)) < 0 ||
659
2.57M
        (code = param_write_bool(plist, "BGPrint", &ppdev->bg_print_requested)) < 0 ||
660
2.57M
        (code = param_write_bool(plist, "ReopenPerPage", &ppdev->ReopenPerPage)) < 0 ||
661
2.57M
        (code = param_write_bool(plist, "pageneutralcolor", &pageneutralcolor)) < 0
662
2.57M
        )
663
0
        return code;
664
665
    /* Force the default to 'memory' if clist file I/O is not included in this build */
666
2.57M
    if (core->clist_io_procs_file == NULL)
667
0
        ppdev->BLS_force_memory = true;
668
2.57M
    if (ppdev->BLS_force_memory) {
669
2.37M
        bls.data = (byte *)"memory";
670
2.37M
        bls.size = 6;
671
2.37M
        bls.persistent = false;
672
2.37M
    } else {
673
193k
        bls.data = (byte *)"file";
674
193k
        bls.size = 4;
675
193k
        bls.persistent = false;
676
193k
    }
677
2.57M
    if( (code = param_write_string(plist, "BandListStorage", &bls)) < 0 )
678
0
        return code;
679
680
2.57M
    ofns.data = (const byte *)ppdev->fname,
681
2.57M
        ofns.size = strlen(ppdev->fname),
682
2.57M
        ofns.persistent = false;
683
2.57M
    if ((code = param_write_string(plist, "OutputFile", &ofns)) < 0)
684
0
        return code;
685
686
    /* Always return an empty string for saved-pages so that get_params followed */
687
    /* by put_params will have no effect.                                       */
688
2.57M
    saved_pages.data = (const byte *)"";
689
2.57M
    saved_pages.size = 0;
690
2.57M
    saved_pages.persistent = false;
691
2.57M
    return param_write_string(plist, "saved-pages", &saved_pages);
692
2.57M
}
693
694
/* Validate an OutputFile name by checking any %-formats. */
695
static int
696
validate_output_file(const gs_param_string * ofs, gs_memory_t *memory)
697
150k
{
698
150k
    gs_parsed_file_name_t parsed;
699
150k
    const char *fmt;
700
701
150k
    return gx_parse_output_file_name(&parsed, &fmt, (const char *)ofs->data,
702
150k
                                     ofs->size, memory) >= 0;
703
150k
}
704
705
/* Put parameters. */
706
int
707
gdev_prn_put_params(gx_device * pdev, gs_param_list * plist)
708
758k
{
709
758k
    gx_device_printer * const ppdev = (gx_device_printer *)pdev;
710
758k
    int ecode = 0;
711
758k
    int code;
712
758k
    const char *param_name;
713
758k
    bool is_open = pdev->is_open;
714
758k
    bool oof = ppdev->OpenOutputFile;
715
758k
    bool rpp = ppdev->ReopenPerPage;
716
758k
    bool old_page_uses_transparency = ppdev->page_uses_transparency;
717
758k
    bool bg_print_requested = ppdev->bg_print_requested;
718
758k
    bool duplex;
719
758k
    int duplex_set = -1;
720
758k
    int width = pdev->width;
721
758k
    int height = pdev->height;
722
758k
    int nthreads = ppdev->num_render_threads_requested;
723
758k
    gdev_space_params save_sp;
724
758k
    gs_param_string ofs;
725
758k
    gs_param_string bls;
726
758k
    gs_param_dict mdict;
727
758k
    gs_param_string saved_pages;
728
758k
    bool pageneutralcolor = false;
729
758k
    gs_lib_ctx_core_t *core = ppdev->memory->gs_lib_ctx->core;
730
731
758k
    memset(&saved_pages, 0, sizeof(gs_param_string));
732
758k
    save_sp = ppdev->space_params;
733
734
758k
    switch (code = param_read_bool(plist, (param_name = "OpenOutputFile"), &oof)) {
735
0
        default:
736
0
            ecode = code;
737
0
            param_signal_error(plist, param_name, ecode);
738
53.7k
        case 0:
739
758k
        case 1:
740
758k
            break;
741
758k
    }
742
743
758k
    switch (code = param_read_bool(plist, (param_name = "ReopenPerPage"), &rpp)) {
744
0
        default:
745
0
            ecode = code;
746
0
            param_signal_error(plist, param_name, ecode);
747
53.7k
        case 0:
748
758k
        case 1:
749
758k
            break;
750
758k
    }
751
752
758k
    if (ppdev->Duplex_set >= 0)  /* i.e., Duplex is supported */
753
0
        switch (code = param_read_bool(plist, (param_name = "Duplex"),
754
0
                                       &duplex)) {
755
0
            case 0:
756
0
                duplex_set = 1;
757
0
                break;
758
0
            default:
759
0
                if ((code = param_read_null(plist, param_name)) == 0) {
760
0
                    duplex_set = 0;
761
0
                    break;
762
0
                }
763
0
                ecode = code;
764
0
                param_signal_error(plist, param_name, ecode);
765
0
            case 1:
766
0
                ;
767
0
        }
768
758k
    switch (code = param_read_string(plist, (param_name = "BandListStorage"), &bls)) {
769
150k
        case 0:
770
            /* Only accept 'file' if the file procs are include in the build */
771
150k
            if ((bls.size > 1) && (bls.data[0] == 'm' ||
772
150k
                 (core->clist_io_procs_file != NULL && bls.data[0] == 'f')))
773
150k
                break;
774
            /* fall through */
775
0
        default:
776
0
            ecode = code;
777
0
            param_signal_error(plist, param_name, ecode);
778
            /* fall through */
779
607k
        case 1:
780
607k
            bls.data = 0;
781
607k
            break;
782
758k
    }
783
784
758k
    switch (code = param_read_string(plist, (param_name = "OutputFile"), &ofs)) {
785
150k
        case 0:
786
150k
            if (pdev->LockSafetyParams &&
787
150k
                    bytes_compare(ofs.data, ofs.size,
788
0
                        (const byte *)ppdev->fname, strlen(ppdev->fname))) {
789
0
                code = gs_error_invalidaccess;
790
0
            }
791
150k
            else
792
150k
                code = validate_output_file(&ofs, pdev->memory);
793
150k
            if (code >= 0)
794
150k
                break;
795
            /* fall through */
796
0
        default:
797
0
            ecode = code;
798
0
            param_signal_error(plist, param_name, ecode);
799
            /* fall through */
800
607k
        case 1:
801
607k
            ofs.data = 0;
802
607k
            break;
803
758k
    }
804
805
    /* Read InputAttributes and OutputAttributes just for the type */
806
    /* check and to indicate that they aren't undefined. */
807
758k
#define read_media(pname)\
808
1.51M
        switch ( code = param_begin_read_dict(plist, (param_name = pname), &mdict, true) )\
809
1.51M
          {\
810
0
          case 0:\
811
0
                param_end_read_dict(plist, pname, &mdict);\
812
0
                break;\
813
0
          default:\
814
0
                ecode = code;\
815
0
                param_signal_error(plist, param_name, ecode);\
816
1.51M
          case 1:\
817
1.51M
                ;\
818
1.51M
          }
819
820
758k
    read_media("InputAttributes");
821
758k
    read_media("OutputAttributes");
822
823
758k
    switch (code = param_read_int(plist, (param_name = "NumRenderingThreads"), &nthreads)) {
824
53.7k
        case 0:
825
53.7k
            break;
826
0
        default:
827
0
            ecode = code;
828
0
            param_signal_error(plist, param_name, ecode);
829
704k
        case 1:
830
704k
            ;
831
758k
    }
832
758k
    switch (code = param_read_bool(plist, (param_name = "BGPrint"),
833
758k
                                                        &bg_print_requested)) {
834
0
        default:
835
0
            ecode = code;
836
0
            param_signal_error(plist, param_name, ecode);
837
53.7k
        case 0:
838
758k
        case 1:
839
758k
            break;
840
758k
    }
841
842
758k
    switch (code = param_read_string(plist, (param_name = "saved-pages"),
843
758k
                                                        &saved_pages)) {
844
0
        default:
845
0
            ecode = code;
846
0
            param_signal_error(plist, param_name, ecode);
847
53.7k
        case 0:
848
758k
        case 1:
849
758k
            break;
850
758k
    }
851
852
    /* NB: put_params to change pageneutralcolor is allowed, but has no effect */
853
    /*     It will be set according the GrayDetection. Allowing it prevents errors */
854
758k
    if (pdev->icc_struct != NULL)
855
700k
        pageneutralcolor = pdev->icc_struct->pageneutralcolor;
856
758k
    if ((code = param_read_bool(plist, (param_name = "pageneutralcolor"),
857
758k
                                                        &pageneutralcolor)) < 0) {
858
0
        ecode = code;
859
0
        param_signal_error(plist, param_name, ecode);
860
0
    }
861
862
758k
    if (ecode < 0)
863
0
        return ecode;
864
    /* Prevent gx_default_put_params from closing the printer. */
865
758k
    pdev->is_open = false;
866
758k
    code = gx_default_put_params(pdev, plist);
867
758k
    pdev->is_open = is_open;
868
758k
    if (code < 0)
869
347
        return code;
870
871
758k
    ppdev->OpenOutputFile = oof;
872
758k
    ppdev->ReopenPerPage = rpp;
873
874
    /* If BGPrint was previously true and it is being turned off, wait for the BG thread */
875
758k
    if (ppdev->bg_print_requested && !bg_print_requested) {
876
0
        prn_finish_bg_print(ppdev);
877
0
    }
878
879
758k
    ppdev->bg_print_requested = bg_print_requested;
880
758k
    if (duplex_set >= 0) {
881
0
        ppdev->Duplex = duplex;
882
0
        ppdev->Duplex_set = duplex_set;
883
0
    }
884
758k
    ppdev->num_render_threads_requested = nthreads;
885
758k
    if (bls.data != 0) {
886
150k
        ppdev->BLS_force_memory = (bls.data[0] == 'm');
887
150k
    }
888
889
    /* If necessary, free and reallocate the printer memory. */
890
    /* Formerly, would not reallocate if device is not open: */
891
    /* we had to patch this out (see News for 5.50). */
892
758k
    code = gdev_prn_maybe_realloc_memory(ppdev, &save_sp, width, height,
893
758k
                                         old_page_uses_transparency);
894
758k
    if (code < 0)
895
0
        return code;
896
897
    /* If filename changed, close file. */
898
758k
    if (ofs.data != 0 &&
899
758k
        bytes_compare(ofs.data, ofs.size,
900
150k
                      (const byte *)ppdev->fname, strlen(ppdev->fname))
901
758k
        ) {
902
        /* Close the file if it's open. */
903
96.8k
        if (ppdev->file != NULL) {
904
0
            gx_device_close_output_file(pdev, ppdev->fname, ppdev->file);
905
0
        }
906
96.8k
        ppdev->file = NULL;
907
96.8k
        if (sizeof(ppdev->fname) <= ofs.size)
908
0
            return_error(gs_error_limitcheck);
909
96.8k
        memcpy(ppdev->fname, ofs.data, ofs.size);
910
96.8k
        ppdev->fname[ofs.size] = 0;
911
96.8k
    }
912
    /* If the device is open and OpenOutputFile is true, */
913
    /* open the OutputFile now.  (If the device isn't open, */
914
    /* this will happen when it is opened.) */
915
758k
    if (pdev->is_open && oof) {
916
0
        code = gdev_prn_open_printer(pdev, 1);
917
0
        if (code < 0)
918
0
            return code;
919
0
    }
920
921
    /* Processing the saved_pages string MAY have side effects, such as printing, */
922
    /* allocating or freeing a list. This is (sort of) a write-only parameter, so */
923
    /* the get_params will always return an empty string (a no-op action).        */
924
758k
    if (saved_pages.data != 0 && saved_pages.size != 0) {
925
0
        return gx_saved_pages_param_process(ppdev, (byte *)saved_pages.data, saved_pages.size);
926
0
    }
927
758k
    return 0;
928
758k
}
929
930
/* ------ Others ------ */
931
932
/* Default routine to (not) override current space_params. */
933
void
934
gx_default_get_space_params(const gx_device_printer *printer_dev,
935
                            gdev_space_params *space_params)
936
155k
{
937
155k
    return;
938
155k
}
939
940
/* Common routine to send the page to the printer.                               */
941
/* If seekable is true, then the printer outputfile must be seekable.            */
942
/* If bg_print_ok is true, the device print_page_copies is compatible with the   */
943
/* background printing, i.e., thread safe and does not change the device.        */
944
/* If the printer device is in 'saved_pages' mode, then background printing is   */
945
/* irrelevant and is ignored. In this case, pages are saved to the list.         */
946
static int  /* 0 ok, -ve error                                               */
947
gdev_prn_output_page_aux(gx_device * pdev, int num_copies, int flush, bool seekable, bool bg_print_ok)
948
75.2k
{
949
75.2k
    gx_device_printer * const ppdev = (gx_device_printer *)pdev;
950
75.2k
    gs_devn_params *pdevn_params;
951
75.2k
    int outcode = 0, errcode = 0, endcode, closecode = 0;
952
75.2k
    int code;
953
954
75.2k
    prn_finish_bg_print(ppdev);   /* finish any previous background printing */
955
956
75.2k
    if (num_copies > 0 && ppdev->saved_pages_list != NULL) {
957
        /* We are putting pages on a list */
958
0
        if ((code = gx_saved_pages_list_add(ppdev)) < 0)
959
0
            return code;
960
961
75.2k
    } else if (num_copies > 0 || !flush) {
962
75.2k
        if ((code = gdev_prn_open_printer_seekable(pdev, 1, seekable)) < 0)
963
0
            return code;
964
965
75.2k
        if (num_copies > 0) {
966
75.2k
            int threads_enabled = 0;
967
75.2k
            int print_foreground = 1;   /* default to foreground printing */
968
969
75.2k
            if (bg_print_ok && PRINTER_IS_CLIST(ppdev) && ppdev->bg_print &&
970
75.2k
                (ppdev->bg_print_requested || ppdev->num_render_threads_requested > 0)) {
971
0
                threads_enabled = clist_enable_multi_thread_render(pdev);
972
0
            }
973
            /* NB: we leave the semaphore allocated until foreground printing or close */
974
            /* If there was an error, abort on this page -- no good way to handle this */
975
            /* but it means that the error will be reported AFTER another page was     */
976
            /* interpreted and written to clist files. FIXME: ???                      */
977
75.2k
            if (ppdev->bg_print && (ppdev->bg_print->return_code < 0)) {
978
0
                outcode = ppdev->bg_print->return_code;
979
0
                threads_enabled = 0;  /* and allow current page to try foreground */
980
0
            }
981
            /* Use 'while' instead of 'if' to avoid nesting */
982
75.2k
            while (ppdev->bg_print_requested && ppdev->bg_print && threads_enabled) {
983
0
                gx_device *ndev;
984
0
                gx_device_printer *npdev;
985
0
                gx_device_clist_reader *crdev = (gx_device_clist_reader *)ppdev;
986
987
0
                if ((code = clist_close_writer_and_init_reader((gx_device_clist *)ppdev)) < 0)
988
                    /* should not happen -- do foreground print */
989
0
                    break;
990
991
                /* We need to hang onto references to these files, so we can ensure the main file data
992
                 * gets freed with the correct allocator.
993
                 */
994
0
                ppdev->bg_print->ocfname =
995
0
                     (char *)gs_alloc_bytes(ppdev->memory->non_gc_memory,
996
0
                           strnlen(crdev->page_info.cfname, gp_file_name_sizeof - 1) + 1, "gdev_prn_output_page_aux(ocfname)");
997
0
                ppdev->bg_print->obfname =
998
0
                     (char *)gs_alloc_bytes(ppdev->memory->non_gc_memory,
999
0
                           strnlen(crdev->page_info.bfname, gp_file_name_sizeof - 1) + 1,"gdev_prn_output_page_aux(ocfname)");
1000
1001
0
                if (!ppdev->bg_print->ocfname || !ppdev->bg_print->obfname)
1002
0
                    break;
1003
1004
0
                strncpy(ppdev->bg_print->ocfname, crdev->page_info.cfname, strnlen(crdev->page_info.cfname, gp_file_name_sizeof - 1) + 1);
1005
0
                strncpy(ppdev->bg_print->obfname, crdev->page_info.bfname, strnlen(crdev->page_info.bfname, gp_file_name_sizeof - 1) + 1);
1006
0
                ppdev->bg_print->obfile = crdev->page_info.bfile;
1007
0
                ppdev->bg_print->ocfile = crdev->page_info.cfile;
1008
0
                ppdev->bg_print->oio_procs = crdev->page_info.io_procs;
1009
0
                crdev->page_info.cfile = crdev->page_info.bfile = NULL;
1010
1011
0
                if (ppdev->bg_print->sema == NULL)
1012
0
                {
1013
0
                    ppdev->bg_print->sema = gx_semaphore_label(gx_semaphore_alloc(ppdev->memory->non_gc_memory), "BGPrint");
1014
0
                    if (ppdev->bg_print->sema == NULL)
1015
0
                        break;     /* couldn't create the semaphore */
1016
0
                }
1017
1018
0
                ndev = setup_device_and_mem_for_thread(pdev->memory->thread_safe_memory, pdev, true, NULL);
1019
0
                if (ndev == NULL) {
1020
0
                    break;
1021
0
                }
1022
0
                ppdev->bg_print->device = ndev;
1023
0
                ppdev->bg_print->num_copies = num_copies;
1024
0
                npdev = (gx_device_printer *)ndev;
1025
0
                npdev->bg_print_requested = 0;
1026
0
                npdev->num_render_threads_requested = ppdev->num_render_threads_requested;
1027
                /* The bgprint's device was created with normal procs, so multi-threaded */
1028
                /* rendering was turned off. Re-enable it now if it is needed.           */
1029
0
                if (npdev->num_render_threads_requested > 0) {
1030
                    /* ignore return code - even if it fails, we'll output the page */
1031
0
                    (void)clist_enable_multi_thread_render(ndev);
1032
0
                }
1033
1034
                /* Now start the thread to print the page */
1035
0
                if ((code = gp_thread_start(prn_print_page_in_background,
1036
0
                                            (void *)(ppdev->bg_print),
1037
0
                                            &(ppdev->bg_print->thread_id))) < 0) {
1038
                    /* Did not start cleanly - clean up is in print_foreground block below */
1039
0
                    break;
1040
0
                }
1041
0
                gp_thread_label(ppdev->bg_print->thread_id, "BG print thread");
1042
                /* Page was succesfully started in bg_print mode */
1043
0
                print_foreground = 0;
1044
                /* Now we need to set up the next page so it will use new clist files */
1045
0
                if ((code = clist_open(pdev)) < 0)   /* this should do it */
1046
                    /* OOPS! can't proceed with the next page */
1047
0
                    return code; /* probably ioerror */
1048
0
                break;       /* exit the while loop */
1049
0
            }
1050
75.2k
            if (print_foreground) {
1051
75.2k
                if (ppdev->bg_print) {
1052
75.2k
                     gs_free_object(ppdev->memory->non_gc_memory, ppdev->bg_print->ocfname, "gdev_prn_output_page_aux(ocfname)");
1053
75.2k
                     gs_free_object(ppdev->memory->non_gc_memory, ppdev->bg_print->obfname, "gdev_prn_output_page_aux(obfname)");
1054
75.2k
                     ppdev->bg_print->ocfname = ppdev->bg_print->obfname = NULL;
1055
1056
                    /* either bg_print was not requested or was not able to start */
1057
75.2k
                    if (ppdev->bg_print->sema != NULL && ppdev->bg_print->device != NULL) {
1058
                        /* There was a problem. Teardown the device and its allocator, but */
1059
                        /* leave the semaphore for possible later use.                     */
1060
0
                        teardown_device_and_mem_for_thread(ppdev->bg_print->device,
1061
0
                                                           ppdev->bg_print->thread_id, true);
1062
0
                        ppdev->bg_print->device = NULL;
1063
0
                    }
1064
75.2k
                }
1065
                /* Here's where we actually let the device's print_page_copies work */
1066
                /* Print the accumulated page description. */
1067
75.2k
                outcode = (*ppdev->printer_procs.print_page_copies)(ppdev, ppdev->file,
1068
75.2k
                                                          num_copies);
1069
75.2k
                gp_fflush(ppdev->file);
1070
75.2k
                errcode = (gp_ferror(ppdev->file) ? gs_note_error(gs_error_ioerror) : 0);
1071
                /* NB: background printing does this differently in its thread */
1072
75.2k
                closecode = gdev_prn_close_printer(pdev);
1073
1074
75.2k
            }
1075
75.2k
        }
1076
75.2k
    }
1077
    /* In the case of a separation device, we need to make sure we */
1078
    /* clear the separation info before the next page starts.      */
1079
75.2k
    pdevn_params = dev_proc(pdev, ret_devn_params)(pdev);
1080
75.2k
    if (pdevn_params != NULL) {
1081
        /* Free up the list of spot names as they were only relevent to that page */
1082
13.4k
        free_separation_names(pdev->memory, &(pdevn_params->separations));
1083
13.4k
        pdevn_params->num_separation_order_names = 0;
1084
13.4k
    }
1085
75.2k
    endcode = (PRINTER_IS_CLIST(ppdev) &&
1086
75.2k
              !((gx_device_clist_common *)ppdev)->do_not_open_or_close_bandfiles ?
1087
75.2k
              clist_finish_page(pdev, flush) : 0);
1088
1089
75.2k
    if (outcode < 0)
1090
9.28k
        return outcode;
1091
65.9k
    if (errcode < 0)
1092
0
        return errcode;
1093
65.9k
    if (endcode < 0)
1094
0
        return endcode;
1095
65.9k
    endcode = gx_finish_output_page(pdev, num_copies, flush);
1096
65.9k
    code = (endcode < 0 ? endcode : closecode < 0 ? closecode : 0);
1097
65.9k
    return code;
1098
65.9k
}
1099
1100
int
1101
gdev_prn_output_page(gx_device * pdev, int num_copies, int flush)
1102
33.2k
{
1103
33.2k
    return(gdev_prn_output_page_aux(pdev, num_copies, flush, false, false));
1104
33.2k
}
1105
1106
int
1107
gdev_prn_output_page_seekable(gx_device * pdev, int num_copies, int flush)
1108
6.13k
{
1109
6.13k
    return(gdev_prn_output_page_aux(pdev, num_copies, flush, true, false));
1110
6.13k
}
1111
1112
int
1113
gdev_prn_bg_output_page(gx_device * pdev, int num_copies, int flush)
1114
35.8k
{
1115
35.8k
    return(gdev_prn_output_page_aux(pdev, num_copies, flush, false, true));
1116
35.8k
}
1117
1118
int
1119
gdev_prn_bg_output_page_seekable(gx_device * pdev, int num_copies, int flush)
1120
0
{
1121
0
    return(gdev_prn_output_page_aux(pdev, num_copies, flush, true, true));
1122
0
}
1123
1124
/* Print a single copy of a page by calling print_page_copies. */
1125
int
1126
gx_print_page_single_copy(gx_device_printer * pdev, gp_file * prn_stream)
1127
0
{
1128
0
    return pdev->printer_procs.print_page_copies(pdev, prn_stream, 1);
1129
0
}
1130
1131
/* Print multiple copies of a page by calling print_page multiple times. */
1132
int
1133
gx_default_print_page_copies(gx_device_printer * pdev, gp_file * prn_stream,
1134
                             int num_copies)
1135
41.9k
{
1136
41.9k
    int i = 1;
1137
41.9k
    int code = 0;
1138
1139
41.9k
    for (; i < num_copies; ++i) {
1140
0
        int errcode, closecode;
1141
1142
0
        code = (*pdev->printer_procs.print_page) (pdev, prn_stream);
1143
0
        if (code < 0)
1144
0
            return code;
1145
        /*
1146
         * Close and re-open the printer, to reset is_new and do the
1147
         * right thing if we're producing multiple output files.
1148
         * Code is mostly copied from gdev_prn_output_page.
1149
         */
1150
0
        gp_fflush(pdev->file);
1151
0
        errcode =
1152
0
            (gp_ferror(pdev->file) ? gs_note_error(gs_error_ioerror) : 0);
1153
0
        closecode = gdev_prn_close_printer((gx_device *)pdev);
1154
0
        pdev->PageCount++;
1155
0
        code = (errcode < 0 ? errcode : closecode < 0 ? closecode :
1156
0
                gdev_prn_open_printer((gx_device *)pdev, true));
1157
0
        if (code < 0) {
1158
0
            pdev->PageCount -= i;
1159
0
            return code;
1160
0
        }
1161
0
        prn_stream = pdev->file;
1162
0
    }
1163
    /* Print the last (or only) page. */
1164
41.9k
    pdev->PageCount -= num_copies - 1;
1165
41.9k
    return (*pdev->printer_procs.print_page) (pdev, prn_stream);
1166
41.9k
}
1167
1168
/*
1169
 * Print a page in the background. When printing is complete,
1170
 * post the return code and signal the foreground (semaphore).
1171
 * This is the procedure that is run in the background thread.
1172
 */
1173
static void
1174
prn_print_page_in_background(void *data)
1175
0
{
1176
0
    bg_print_t *bg_print = (bg_print_t *)data;
1177
0
    int code, errcode = 0;
1178
0
    int num_copies = bg_print->num_copies;
1179
0
    gx_device_printer *ppdev = (gx_device_printer *)bg_print->device;
1180
1181
0
    code = (*ppdev->printer_procs.print_page_copies)(ppdev, ppdev->file,
1182
0
                                                          num_copies);
1183
0
    gp_fflush(ppdev->file);
1184
1185
0
    errcode = (gp_ferror(ppdev->file) ? gs_note_error(gs_error_ioerror) : 0);
1186
0
    bg_print->return_code = code < 0 ? code : errcode;
1187
1188
    /* Finally, release the foreground that may be waiting */
1189
0
    gx_semaphore_signal(bg_print->sema);
1190
0
}
1191
/* ---------------- Driver services ---------------- */
1192
1193
/* Initialize a rendering plane specification. */
1194
int
1195
gx_render_plane_init(gx_render_plane_t *render_plane, const gx_device *dev,
1196
                     int index)
1197
0
{
1198
    /*
1199
     * Eventually the computation of shift and depth from dev and index
1200
     * will be made device-dependent.
1201
     */
1202
0
    int num_planes = dev->color_info.num_components;
1203
0
    int plane_depth = dev->color_info.depth / num_planes;
1204
1205
0
    if (index < -1 || index >= num_planes)
1206
0
        return_error(gs_error_rangecheck);
1207
0
    render_plane->index = index;
1208
0
    if (index == -1) {
1209
        /* No plane, chunky results required. */
1210
0
        render_plane->depth = dev->color_info.depth;
1211
0
        render_plane->shift = 0;
1212
0
    } else {
1213
        /* A single plane */
1214
0
        render_plane->depth = plane_depth;
1215
0
        render_plane->shift = plane_depth * (num_planes - 1 - index);
1216
0
    }
1217
0
    return 0;
1218
0
}
1219
1220
/* Clear trailing bits in the last byte of (a) scan line(s). */
1221
void
1222
gdev_prn_clear_trailing_bits(byte *data, uint raster, int height,
1223
                             const gx_device *dev)
1224
0
{
1225
0
    int first_bit = dev->width * dev->color_info.depth;
1226
1227
0
    if (first_bit & 7)
1228
0
        bits_fill_rectangle(data, first_bit, raster, mono_fill_make_pattern(0),
1229
0
                            -first_bit & 7, height);
1230
0
}
1231
1232
/* Return the number of scan lines that should actually be passed */
1233
/* to the device. */
1234
int
1235
gdev_prn_print_scan_lines(gx_device * pdev)
1236
0
{
1237
0
    int height = pdev->height;
1238
0
    gs_matrix imat;
1239
0
    float yscale;
1240
0
    int top, bottom, offset, end;
1241
1242
0
    (*dev_proc(pdev, get_initial_matrix)) (pdev, &imat);
1243
0
    yscale = imat.yy * 72.0;  /* Y dpi, may be negative */
1244
0
    top = (int)(dev_t_margin(pdev) * yscale);
1245
0
    bottom = (int)(dev_b_margin(pdev) * yscale);
1246
0
    offset = (int)(dev_y_offset(pdev) * yscale);
1247
0
    if (yscale < 0) {   /* Y=0 is top of page */
1248
0
        end = -offset + height + bottom;
1249
0
    } else {     /* Y=0 is bottom of page */
1250
0
        end = offset + height - top;
1251
0
    }
1252
0
    return min(height, end);
1253
0
}
1254
1255
/* Open the current page for printing. */
1256
int
1257
gdev_prn_open_printer_seekable(gx_device *pdev, bool binary_mode,
1258
                               bool seekable)
1259
75.2k
{
1260
75.2k
    gx_device_printer * const ppdev = (gx_device_printer *)pdev;
1261
1262
75.2k
    if (ppdev->file != 0) {
1263
30.4k
        ppdev->file_is_new = false;
1264
30.4k
        return 0;
1265
30.4k
    }
1266
44.7k
    {
1267
44.7k
        int code = gx_device_open_output_file(pdev, ppdev->fname,
1268
44.7k
                                              binary_mode, seekable,
1269
44.7k
                                              &ppdev->file);
1270
44.7k
        if (code < 0)
1271
0
            return code;
1272
1273
44.7k
        if (seekable && !gp_fseekable(ppdev->file)) {
1274
0
            errprintf(pdev->memory, "I/O Error: Output File \"%s\" must be seekable\n", ppdev->fname);
1275
0
            if (!IS_LIBCTX_STDOUT(pdev->memory, gp_get_file(ppdev->file))
1276
0
              && !IS_LIBCTX_STDERR(pdev->memory, gp_get_file(ppdev->file))) {
1277
1278
0
                code = gx_device_close_output_file(pdev, ppdev->fname, ppdev->file);
1279
0
                ppdev->file = NULL;
1280
0
                if (code < 0)
1281
0
                    return code;
1282
0
            }
1283
0
            ppdev->file = NULL;
1284
1285
0
            return_error(gs_error_ioerror);
1286
0
        }
1287
44.7k
    }
1288
44.7k
    ppdev->file_is_new = true;
1289
1290
44.7k
    return 0;
1291
44.7k
}
1292
int
1293
gdev_prn_open_printer(gx_device *pdev, bool binary_mode)
1294
0
{
1295
0
    return gdev_prn_open_printer_seekable(pdev, binary_mode, false);
1296
0
}
1297
1298
/*
1299
 * Test whether the printer's output file was just opened, i.e., whether
1300
 * this is the first page being written to this file.  This is only valid
1301
 * at the entry to a driver's print_page procedure.
1302
 */
1303
bool
1304
gdev_prn_file_is_new(const gx_device_printer *pdev)
1305
0
{
1306
0
    return pdev->file_is_new;
1307
0
}
1308
1309
/* Determine the colors used in a range of lines. */
1310
/* FIXME: Currently, the page_info is ignored and the page_info from
1311
 * the 'dev' parameter is used. For saved pages, the 'dev' may not
1312
 * be a clist and the page_info should be used for clist file info
1313
 * which may require a dummy gx_device_printer with the page_info
1314
 * copied from the caller's data.
1315
 */
1316
int
1317
gx_page_info_color_usage(const gx_device *dev,
1318
                         const gx_band_page_info_t *page_info,
1319
                         int y, int height,
1320
                         gx_color_usage_t *color_usage, int *range_start)
1321
0
{
1322
0
    gx_device_clist_reader *crdev = (gx_device_clist_reader *)dev;
1323
0
    int start, end, i;
1324
0
    int band_height = page_info->band_params.BandHeight;
1325
0
    gx_color_usage_bits or = 0;
1326
0
    bool slow_rop = false;
1327
1328
0
    if (y < 0 || height < 0 || height > dev->height - y)
1329
0
        return -1;
1330
0
    start = y / band_height;
1331
0
    end = (y + height + band_height - 1) / band_height;
1332
0
    if (crdev->color_usage_array == NULL) {
1333
0
        return -1;
1334
0
    }
1335
0
    for (i = start; i < end; ++i) {
1336
0
        or |= crdev->color_usage_array[i].or;
1337
0
        slow_rop |= crdev->color_usage_array[i].slow_rop;
1338
0
    }
1339
0
    color_usage->or = or;
1340
0
    color_usage->slow_rop = slow_rop;
1341
0
    *range_start = start * band_height;
1342
0
    return min(end * band_height, dev->height) - *range_start;
1343
0
}
1344
int
1345
gdev_prn_color_usage(gx_device *dev, int y, int height,
1346
                     gx_color_usage_t *color_usage, int *range_start)
1347
0
{
1348
0
    gx_device_printer *pdev = (gx_device_printer *)dev;
1349
0
    gx_device_clist *cdev = (gx_device_clist *)dev;
1350
0
    gx_device_clist_writer *cldev = (gx_device_clist_writer *)dev;
1351
1352
    /* If this isn't a banded device, return default values. */
1353
0
    if (!PRINTER_IS_CLIST(pdev)) {
1354
0
        *range_start = 0;
1355
0
        color_usage->or = gx_color_usage_all(dev);
1356
0
        return dev->height;
1357
0
    }
1358
0
    if (y < 0 || height < 0 || height > dev->height - y)
1359
0
        return -1;
1360
0
    if (CLIST_IS_WRITER(cdev)) {
1361
        /* Not expected to be used since usually this is called during reading */
1362
0
        return clist_writer_color_usage(cldev, y, height, color_usage, range_start);
1363
0
    } else
1364
0
        return gx_page_info_color_usage(dev, &cldev->page_info,
1365
0
                                 y, height, color_usage, range_start);
1366
0
}
1367
1368
/*
1369
 * Create the buffer device for a printer device.  Clients should always
1370
 * call this, and never call the device procedure directly.
1371
 */
1372
int
1373
gdev_create_buf_device(create_buf_device_proc_t cbd_proc, gx_device **pbdev,
1374
                       gx_device *target, int y,
1375
                       const gx_render_plane_t *render_plane,
1376
                       gs_memory_t *mem, gx_color_usage_t *color_usage)
1377
160M
{
1378
160M
    int code = cbd_proc(pbdev, target, y, render_plane, mem, color_usage);
1379
1380
160M
    if (code < 0)
1381
0
        return code;
1382
    /* Retain this device -- it will be freed explicitly. */
1383
160M
    gx_device_retain(*pbdev, true);
1384
160M
    return code;
1385
160M
}
1386
1387
/*
1388
 * Create an ordinary memory device for page or band buffering,
1389
 * possibly preceded by a plane extraction device.
1390
 */
1391
int
1392
gx_default_create_buf_device(gx_device **pbdev, gx_device *target, int y,
1393
    const gx_render_plane_t *render_plane, gs_memory_t *mem, gx_color_usage_t *color_usage)
1394
161M
{
1395
161M
    int plane_index = (render_plane ? render_plane->index : -1);
1396
161M
    int depth;
1397
161M
    const gx_device_memory *mdproto;
1398
161M
    gx_device_memory *mdev;
1399
161M
    gx_device *bdev;
1400
1401
161M
    if (plane_index >= 0)
1402
0
        depth = render_plane->depth;
1403
161M
    else {
1404
161M
        depth = target->color_info.depth;
1405
161M
        if (target->num_planar_planes)
1406
7.65M
            depth /= target->num_planar_planes;
1407
161M
    }
1408
1409
161M
    mdproto = gdev_mem_device_for_bits(depth);
1410
161M
    if (mdproto == 0)
1411
0
        return_error(gs_error_rangecheck);
1412
161M
    if (mem) {
1413
160M
        mdev = gs_alloc_struct_immovable(mem, gx_device_memory, &st_device_memory,
1414
160M
                               "create_buf_device");
1415
160M
        if (mdev == 0)
1416
0
            return_error(gs_error_VMerror);
1417
160M
    } else {
1418
1.35M
        mdev = (gx_device_memory *)*pbdev;
1419
1.35M
    }
1420
161M
    if (target == (gx_device *)mdev) {
1421
0
        dev_t_proc_dev_spec_op((*orig_dso), gx_device) = dev_proc(mdev, dev_spec_op);
1422
        /* The following is a special hack for setting up printer devices. */
1423
0
        assign_dev_procs(mdev, mdproto);
1424
0
        mdev->initialize_device_procs = mdproto->initialize_device_procs;
1425
0
        mdev->initialize_device_procs((gx_device *)mdev);
1426
        /* We know mdev->procs.initialize_device is NULL! */
1427
        /* Do not override the dev_spec_op! */
1428
0
        dev_proc(mdev, dev_spec_op) = orig_dso;
1429
0
        check_device_separable((gx_device *)mdev);
1430
        /* In order for saved-pages to work, we need to hook the dev_spec_op */
1431
0
        if (mdev->procs.dev_spec_op == NULL || mdev->procs.dev_spec_op == gx_default_dev_spec_op)
1432
0
            set_dev_proc(mdev, dev_spec_op, gdev_prn_dev_spec_op);
1433
#ifdef DEBUG
1434
        /* scanning sources didn't show anything, but if a device gets changed or added */
1435
        /* that has its own dev_spec_op, it should call the gdev_prn_spec_op as well    */
1436
        else {
1437
            if (dev_proc(mdev, dev_spec_op)((gx_device *)mdev, gxdso_debug_printer_check, NULL, 0) < 0)
1438
                errprintf(mdev->memory, "Warning: printer device has private dev_spec_op\n");
1439
        }
1440
#endif
1441
0
        gx_device_fill_in_procs((gx_device *)mdev);
1442
161M
    } else {
1443
161M
        gs_devn_params* pdevn_params;
1444
1445
161M
        gs_make_mem_device(mdev, mdproto, mem, (color_usage == NULL ? 1 : 0), target);
1446
        /* mem devices may need to refer to the target's devn_params struct */
1447
        /* if the device has separations already defined (by SeparationOrderNames), we   */
1448
        /* need to use them so the colorants are in the same order as the target device. */
1449
161M
        pdevn_params = dev_proc(target, ret_devn_params)(target);
1450
161M
        if (pdevn_params != NULL) {
1451
7.65M
            mdev->procs.ret_devn_params = gx_forward_ret_devn_params;
1452
7.65M
        }
1453
161M
    }
1454
161M
    mdev->width = target->width;
1455
161M
    mdev->band_y = y;
1456
161M
    mdev->log2_align_mod = target->log2_align_mod;
1457
161M
    mdev->pad = target->pad;
1458
161M
    mdev->num_planar_planes = target->num_planar_planes;
1459
    /*
1460
     * The matrix in the memory device is irrelevant,
1461
     * because all we do with the device is call the device-level
1462
     * output procedures, but we may as well set it to
1463
     * something halfway reasonable.
1464
     */
1465
161M
    gs_deviceinitialmatrix(target, &mdev->initial_matrix);
1466
161M
    if (plane_index >= 0) {
1467
0
        gx_device_plane_extract *edev;
1468
1469
        /* Guard against potential NULL dereference in gs_alloc_struct */
1470
0
        if (!mem)
1471
0
            return_error(gs_error_undefined);
1472
1473
0
        edev = gs_alloc_struct(mem, gx_device_plane_extract,
1474
0
                            &st_device_plane_extract, "create_buf_device");
1475
1476
0
        if (edev == 0) {
1477
0
            gx_default_destroy_buf_device((gx_device *)mdev);
1478
0
            return_error(gs_error_VMerror);
1479
0
        }
1480
0
        edev->memory = mem;
1481
0
        plane_device_init(edev, target, (gx_device *)mdev, render_plane,
1482
0
                          false);
1483
0
        bdev = (gx_device *)edev;
1484
0
    } else
1485
161M
        bdev = (gx_device *)mdev;
1486
    /****** QUESTIONABLE, BUT BETTER THAN OMITTING ******/
1487
161M
    if (&bdev->color_info != &target->color_info) /* Pacify Valgrind */
1488
161M
        bdev->color_info = target->color_info;
1489
161M
    *pbdev = bdev;
1490
161M
    return 0;
1491
161M
}
1492
1493
/* Determine the space needed by the buffer device. */
1494
int
1495
gx_default_size_buf_device(gx_device_buf_space_t *space, gx_device *target,
1496
                           const gx_render_plane_t *render_plane,
1497
                           int height, bool not_used)
1498
195k
{
1499
195k
    gx_device_memory mdev;
1500
1501
195k
    space->line_ptrs = 0; /*        */
1502
195k
    space->bits = 0;    /* clear in case of failure */
1503
195k
    space->raster = 0;    /*        */
1504
195k
    mdev.color_info.depth =
1505
195k
        (render_plane && render_plane->index >= 0 ? render_plane->depth :
1506
195k
         target->color_info.depth);
1507
195k
    mdev.color_info.num_components = target->color_info.num_components;
1508
195k
    mdev.width = target->width;
1509
195k
    mdev.num_planar_planes = target->num_planar_planes;
1510
195k
    mdev.pad = target->pad;
1511
195k
    mdev.log2_align_mod = target->log2_align_mod;
1512
195k
    if (gdev_mem_bits_size(&mdev, target->width, height, &(space->bits)) < 0)
1513
0
        return_error(gs_error_VMerror);
1514
195k
    space->line_ptrs = gdev_mem_line_ptrs_size(&mdev, target->width, height);
1515
195k
    space->raster = gdev_mem_raster(&mdev);
1516
195k
    return 0;
1517
195k
}
1518
1519
/* Set up the buffer device. */
1520
int
1521
gx_default_setup_buf_device(gx_device *bdev, byte *buffer, int raster,
1522
                            byte **line_ptrs, int y, int setup_height,
1523
                            int full_height)
1524
163M
{
1525
163M
    gx_device_memory *mdev =
1526
163M
        (gs_device_is_memory(bdev) ? (gx_device_memory *)bdev :
1527
163M
         (gx_device_memory *)(((gx_device_plane_extract *)bdev)->plane_dev));
1528
163M
    byte **ptrs = line_ptrs;
1529
163M
    int code;
1530
1531
163M
    if (ptrs == 0) {
1532
        /*
1533
         * Before allocating a new line pointer array, if there is a previous
1534
         * array, free it to prevent leaks.
1535
         */
1536
0
        if (mdev->line_ptrs != NULL)
1537
0
            gs_free_object(mdev->line_pointer_memory, mdev->line_ptrs,
1538
0
                       "mem_close");
1539
        /*
1540
         * Allocate line pointers now; free them when we close the device.
1541
         * Note that for multi-planar devices, we have to allocate using
1542
         * full_height rather than setup_height.
1543
         */
1544
0
        ptrs = (byte **)
1545
0
            gs_alloc_byte_array(mdev->memory,
1546
0
                                (mdev->num_planar_planes ?
1547
0
                                 full_height * mdev->num_planar_planes :
1548
0
                                 setup_height),
1549
0
                                sizeof(byte *), "setup_buf_device");
1550
0
        if (ptrs == 0)
1551
0
            return_error(gs_error_VMerror);
1552
0
        mdev->line_pointer_memory = mdev->memory;
1553
0
        mdev->foreign_line_pointers = false;
1554
0
    }
1555
163M
    mdev->height = full_height;
1556
163M
    code = gdev_mem_set_line_ptrs(mdev, buffer + raster * y, raster,
1557
163M
                                  ptrs, setup_height);
1558
163M
    mdev->height = setup_height;
1559
163M
    bdev->height = setup_height; /* do here in case mdev == bdev */
1560
163M
    return code;
1561
163M
}
1562
1563
/* Destroy the buffer device. */
1564
void
1565
gx_default_destroy_buf_device(gx_device *bdev)
1566
160M
{
1567
160M
    gx_device *mdev = bdev;
1568
1569
160M
    if (!gs_device_is_memory(bdev)) {
1570
        /* bdev must be a plane extraction device. */
1571
0
        mdev = ((gx_device_plane_extract *)bdev)->plane_dev;
1572
0
        gs_free_object(bdev->memory, bdev, "destroy_buf_device");
1573
0
    }
1574
    /* gs_free_object will do finalize which will decrement icc profile */
1575
160M
    dev_proc(mdev, close_device)(mdev);
1576
160M
    gs_free_object(mdev->memory, mdev, "destroy_buf_device");
1577
160M
}
1578
1579
/*
1580
 * Copy one or more rasterized scan lines to a buffer, or return a pointer
1581
 * to them.  See gdevprn.h for detailed specifications.
1582
 */
1583
int
1584
gdev_prn_get_lines(gx_device_printer *pdev, int y, int height,
1585
                   byte *buffer, uint bytes_per_line,
1586
                   byte **actual_buffer, uint *actual_bytes_per_line,
1587
                   const gx_render_plane_t *render_plane)
1588
0
{
1589
0
    int code;
1590
0
    gs_int_rect rect;
1591
0
    gs_get_bits_params_t params;
1592
0
    int plane;
1593
1594
0
    if (y < 0 || height < 0 || y + height > pdev->height)
1595
0
        return_error(gs_error_rangecheck);
1596
0
    rect.p.x = 0, rect.p.y = y;
1597
0
    rect.q.x = pdev->width, rect.q.y = y + height;
1598
0
    params.options =
1599
0
        GB_RETURN_POINTER | GB_ALIGN_STANDARD | GB_OFFSET_0 |
1600
0
        GB_RASTER_ANY |
1601
        /* No depth specified, we always use native colors. */
1602
0
        GB_COLORS_NATIVE | GB_ALPHA_NONE;
1603
0
    if (render_plane) {
1604
0
        params.options |= GB_PACKING_PLANAR | GB_SELECT_PLANES;
1605
0
        memset(params.data, 0,
1606
0
               sizeof(params.data[0]) * pdev->color_info.num_components);
1607
0
        plane = render_plane->index;
1608
0
        params.data[plane] = buffer;
1609
0
    } else {
1610
0
        params.options |= GB_PACKING_CHUNKY;
1611
0
        params.data[0] = buffer;
1612
0
        plane = 0;
1613
0
    }
1614
0
    params.x_offset = 0;
1615
0
    params.raster = bytes_per_line;
1616
0
    code = dev_proc(pdev, get_bits_rectangle)
1617
0
        ((gx_device *)pdev, &rect, &params);
1618
0
    if (code < 0 && actual_buffer) {
1619
        /*
1620
         * RETURN_POINTER might not be implemented for this
1621
         * combination of parameters: try RETURN_COPY.
1622
         */
1623
0
        params.options &= ~(GB_RETURN_POINTER | GB_RASTER_ALL);
1624
0
        params.options |= GB_RETURN_COPY | GB_RASTER_SPECIFIED;
1625
0
        code = dev_proc(pdev, get_bits_rectangle)
1626
0
            ((gx_device *)pdev, &rect, &params);
1627
0
    }
1628
0
    if (code < 0)
1629
0
        return code;
1630
0
    if (actual_buffer)
1631
0
        *actual_buffer = params.data[plane];
1632
0
    if (actual_bytes_per_line)
1633
0
        *actual_bytes_per_line = params.raster;
1634
0
    return code;
1635
0
}
1636
1637
/* Copy a scan line from the buffer to the printer. */
1638
int
1639
gdev_prn_get_bits(gx_device_printer * pdev, int y, byte * str, byte ** actual_data)
1640
130M
{
1641
130M
    int code;
1642
130M
    uint line_size = gdev_prn_raster(pdev);
1643
130M
    int last_bits = -(pdev->width * pdev->color_info.depth) & 7;
1644
130M
    gs_int_rect rect;
1645
130M
    gs_get_bits_params_t params;
1646
1647
130M
    rect.p.x = 0;
1648
130M
    rect.p.y = y;
1649
130M
    rect.q.x = pdev->width;
1650
130M
    rect.q.y = y+1;
1651
1652
130M
    params.options = (GB_ALIGN_ANY |
1653
130M
                      GB_RETURN_COPY |
1654
130M
                      GB_OFFSET_0 |
1655
130M
                      GB_RASTER_STANDARD | GB_PACKING_CHUNKY |
1656
130M
                      GB_COLORS_NATIVE | GB_ALPHA_NONE);
1657
130M
    if (actual_data)
1658
97.8M
        params.options |=  GB_RETURN_POINTER;
1659
130M
    params.x_offset = 0;
1660
130M
    params.raster = bitmap_raster(pdev->width * pdev->color_info.depth);
1661
130M
    params.data[0] = str;
1662
130M
    code = (*dev_proc(pdev, get_bits_rectangle))((gx_device *)pdev, &rect,
1663
130M
                                                 &params);
1664
130M
    if (code < 0)
1665
6
        return code;
1666
130M
    if (actual_data)
1667
97.8M
        *actual_data = params.data[0];
1668
130M
    if (last_bits != 0) {
1669
56.1M
        byte *dest = (actual_data != NULL ? *actual_data : str);
1670
1671
56.1M
        dest[line_size - 1] &= 0xff << last_bits;
1672
56.1M
    }
1673
130M
    return 0;
1674
130M
}
1675
/* Copy scan lines to a buffer.  Return the number of scan lines, */
1676
/* or <0 if error.  This procedure is DEPRECATED. */
1677
/* Some old and contrib drivers ignore error codes, so make sure and fill */
1678
/* remaining lines if we get an error (and for lines past end of page).   */
1679
int
1680
gdev_prn_copy_scan_lines(gx_device_printer * pdev, int y, byte * str, uint size)
1681
33.1M
{
1682
33.1M
    uint line_size = gdev_prn_raster(pdev);
1683
33.1M
    int requested_count = 0;
1684
33.1M
    int i, count;
1685
33.1M
    int code = 0;
1686
33.1M
    byte *dest = str;
1687
1688
33.1M
    if (line_size != 0)
1689
33.1M
        requested_count = size / line_size;
1690
1691
    /* Clamp count between 0 and remaining lines on page so we don't return < 0 */
1692
    /* unless gdev_prn_get_bits returns an error */
1693
33.1M
    count = max(0, min(requested_count, pdev->height - y));
1694
66.3M
    for (i = 0; i < count; i++, dest += line_size) {
1695
33.1M
        code = gdev_prn_get_bits(pdev, y + i, dest, NULL);
1696
33.1M
        if (code < 0)
1697
4
            break; /* will fill remaining lines and return code outside the loop */
1698
33.1M
    }
1699
    /* fill remaining lines with 0's to prevent printing garbage */
1700
33.1M
    memset(dest, 0, (size_t)line_size * (requested_count - i));
1701
33.1M
    return (code < 0 ) ? code : count;
1702
33.1M
}
1703
1704
/* Close the current page. */
1705
int
1706
gdev_prn_close_printer(gx_device * pdev)
1707
75.2k
{
1708
75.2k
    gx_device_printer * const ppdev = (gx_device_printer *)pdev;
1709
75.2k
    gs_parsed_file_name_t parsed;
1710
75.2k
    const char *fmt;
1711
75.2k
    int code = gx_parse_output_file_name(&parsed, &fmt, ppdev->fname,
1712
75.2k
                                         strlen(ppdev->fname), pdev->memory);
1713
1714
75.2k
    if ((code >= 0 && fmt) /* file per page */ ||
1715
75.2k
        ppdev->ReopenPerPage  /* close and reopen for each page */
1716
75.2k
        ) {
1717
0
        gx_device_close_output_file(pdev, ppdev->fname, ppdev->file);
1718
0
        ppdev->file = NULL;
1719
0
    }
1720
75.2k
    return 0;
1721
75.2k
}
1722
1723
/* If necessary, free and reallocate the printer memory after changing params */
1724
int
1725
gdev_prn_maybe_realloc_memory(gx_device_printer *prdev,
1726
                              gdev_space_params *old_sp,
1727
                              int old_width, int old_height,
1728
                              bool old_page_uses_transparency)
1729
1.00M
{
1730
1.00M
    int code = 0;
1731
1.00M
    gx_device *const pdev = (gx_device *)prdev;
1732
    /*gx_device_memory * const mdev = (gx_device_memory *)prdev;*/
1733
1734
    /*
1735
     * The first test was changed to mdev->base != 0 in 5.50 (per Artifex).
1736
     * Not only was this test wrong logically, it was incorrect in that
1737
     * casting pdev to a (gx_device_memory *) is only meaningful if banding
1738
     * is not being used.  The test was changed back to prdev->is_open in
1739
     * 5.67 (also per Artifex).  For more information, see the News items
1740
     * for these filesets.
1741
     */
1742
1.00M
    if (prdev->is_open &&
1743
1.00M
        (gdev_space_params_cmp(prdev->space_params, *old_sp) != 0 ||
1744
815k
         prdev->width != old_width || prdev->height != old_height ||
1745
815k
         prdev->page_uses_transparency != old_page_uses_transparency)
1746
1.00M
        ) {
1747
130k
        int new_width = prdev->width;
1748
130k
        int new_height = prdev->height;
1749
130k
        gdev_space_params new_sp;
1750
1751
#ifdef DEBUGGING_HACKS
1752
debug_dump_bytes(pdev->memory, (const byte *)old_sp, (const byte *)(old_sp + 1), "old");
1753
debug_dump_bytes(pddev->memory, (const byte *)&prdev->space_params,
1754
                 (const byte *)(&prdev->space_params + 1), "new");
1755
dmprintf4(pdev->memory, "w=%d/%d, h=%d/%d\n", old_width, new_width, old_height, new_height);
1756
#endif /*DEBUGGING_HACKS*/
1757
130k
        new_sp = prdev->space_params;
1758
130k
        prdev->width = old_width;
1759
130k
        prdev->height = old_height;
1760
130k
        prdev->space_params = *old_sp;
1761
130k
        code = gdev_prn_reallocate_memory(pdev, &new_sp,
1762
130k
                                          new_width, new_height);
1763
        /* If this fails, device should be usable w/old params, but */
1764
        /* band files may not be open. */
1765
130k
    }
1766
1.00M
    return code;
1767
1.00M
}
1768
1769
void
1770
gdev_prn_initialize_device_procs(gx_device *dev)
1771
63.7k
{
1772
63.7k
    set_dev_proc(dev, open_device, gdev_prn_open);
1773
63.7k
    set_dev_proc(dev, close_device, gdev_prn_close);
1774
63.7k
    set_dev_proc(dev, output_page, gdev_prn_output_page);
1775
63.7k
    set_dev_proc(dev, get_params, gdev_prn_get_params);
1776
63.7k
    set_dev_proc(dev, put_params, gdev_prn_put_params);
1777
63.7k
    set_dev_proc(dev, get_page_device, gx_page_device_get_page_device);
1778
63.7k
    set_dev_proc(dev, dev_spec_op, gdev_prn_dev_spec_op);
1779
63.7k
    set_dev_proc(dev, map_rgb_color, gdev_prn_map_rgb_color);
1780
63.7k
    set_dev_proc(dev, map_color_rgb, gdev_prn_map_color_rgb);
1781
63.7k
    set_dev_proc(dev, encode_color, gdev_prn_map_rgb_color);
1782
63.7k
    set_dev_proc(dev, decode_color, gdev_prn_map_color_rgb);
1783
63.7k
}
1784
1785
void gdev_prn_initialize_device_procs_bg(gx_device *dev)
1786
10.5k
{
1787
10.5k
    gdev_prn_initialize_device_procs(dev);
1788
1789
10.5k
    set_dev_proc(dev, output_page, gdev_prn_bg_output_page);
1790
10.5k
}
1791
1792
void
1793
gdev_prn_initialize_device_procs_mono(gx_device *dev)
1794
28.9k
{
1795
28.9k
    gdev_prn_initialize_device_procs(dev);
1796
1797
28.9k
    set_dev_proc(dev, map_rgb_color, gdev_prn_map_rgb_color);
1798
28.9k
    set_dev_proc(dev, map_color_rgb, gdev_prn_map_color_rgb);
1799
28.9k
    set_dev_proc(dev, encode_color, gdev_prn_map_rgb_color);
1800
28.9k
    set_dev_proc(dev, decode_color, gdev_prn_map_color_rgb);
1801
28.9k
}
1802
1803
void gdev_prn_initialize_device_procs_mono_bg(gx_device *dev)
1804
19.1k
{
1805
19.1k
    gdev_prn_initialize_device_procs_mono(dev);
1806
1807
19.1k
    set_dev_proc(dev, output_page, gdev_prn_bg_output_page);
1808
19.1k
}
1809
1810
void
1811
gdev_prn_initialize_device_procs_gray(gx_device *dev)
1812
0
{
1813
0
    gdev_prn_initialize_device_procs(dev);
1814
1815
0
    set_dev_proc(dev, map_rgb_color, gx_default_gray_map_rgb_color);
1816
0
    set_dev_proc(dev, map_color_rgb, gx_default_gray_map_color_rgb);
1817
0
    set_dev_proc(dev, encode_color, gx_default_gray_encode_color);
1818
0
    set_dev_proc(dev, decode_color, gx_default_gray_decode_color);
1819
0
}
1820
1821
void gdev_prn_initialize_device_procs_gray_bg(gx_device *dev)
1822
0
{
1823
0
    gdev_prn_initialize_device_procs_gray(dev);
1824
1825
0
    set_dev_proc(dev, output_page, gdev_prn_bg_output_page);
1826
0
}
1827
1828
void gdev_prn_initialize_device_procs_rgb(gx_device *dev)
1829
14.3k
{
1830
14.3k
    gdev_prn_initialize_device_procs(dev);
1831
1832
14.3k
    set_dev_proc(dev, map_rgb_color, gx_default_rgb_map_rgb_color);
1833
14.3k
    set_dev_proc(dev, map_color_rgb, gx_default_rgb_map_color_rgb);
1834
14.3k
    set_dev_proc(dev, encode_color, gx_default_rgb_map_rgb_color);
1835
14.3k
    set_dev_proc(dev, decode_color, gx_default_rgb_map_color_rgb);
1836
14.3k
}
1837
1838
void gdev_prn_initialize_device_procs_rgb_bg(gx_device *dev)
1839
9.20k
{
1840
9.20k
    gdev_prn_initialize_device_procs_rgb(dev);
1841
1842
9.20k
    set_dev_proc(dev, output_page, gdev_prn_bg_output_page);
1843
9.20k
}
1844
1845
void
1846
gdev_prn_initialize_device_procs_gray8(gx_device *dev)
1847
1.04k
{
1848
1.04k
    gdev_prn_initialize_device_procs(dev);
1849
1850
1.04k
    set_dev_proc(dev, map_rgb_color, gx_default_8bit_map_gray_color);
1851
1.04k
    set_dev_proc(dev, map_color_rgb, gx_default_8bit_map_color_gray);
1852
1.04k
    set_dev_proc(dev, encode_color, gx_default_8bit_map_gray_color);
1853
1.04k
    set_dev_proc(dev, decode_color, gx_default_8bit_map_color_gray);
1854
1.04k
}
1855
1856
void gdev_prn_initialize_device_procs_gray8_bg(gx_device *dev)
1857
0
{
1858
0
    gdev_prn_initialize_device_procs_gray8(dev);
1859
1860
0
    set_dev_proc(dev, output_page, gdev_prn_bg_output_page);
1861
0
}
1862
1863
void gdev_prn_initialize_device_procs_cmyk1(gx_device *dev)
1864
0
{
1865
0
    gdev_prn_initialize_device_procs(dev);
1866
1867
0
    set_dev_proc(dev, map_cmyk_color, cmyk_1bit_map_cmyk_color);
1868
0
    set_dev_proc(dev, map_color_rgb, cmyk_1bit_map_color_rgb);
1869
0
    set_dev_proc(dev, encode_color, cmyk_1bit_map_cmyk_color);
1870
0
    set_dev_proc(dev, decode_color, cmyk_1bit_map_color_cmyk);
1871
0
}
1872
1873
void gdev_prn_initialize_device_procs_cmyk1_bg(gx_device *dev)
1874
0
{
1875
0
    gdev_prn_initialize_device_procs_cmyk1(dev);
1876
1877
0
    set_dev_proc(dev, output_page, gdev_prn_bg_output_page);
1878
0
}
1879
1880
void gdev_prn_initialize_device_procs_cmyk8(gx_device *dev)
1881
0
{
1882
0
    gdev_prn_initialize_device_procs(dev);
1883
1884
0
    set_dev_proc(dev, map_cmyk_color, cmyk_8bit_map_cmyk_color);
1885
0
    set_dev_proc(dev, map_color_rgb, cmyk_8bit_map_color_rgb);
1886
0
    set_dev_proc(dev, encode_color, cmyk_8bit_map_cmyk_color);
1887
0
    set_dev_proc(dev, decode_color, cmyk_8bit_map_color_cmyk);
1888
0
}
1889
1890
void gdev_prn_initialize_device_procs_cmyk8_bg(gx_device *dev)
1891
0
{
1892
0
    gdev_prn_initialize_device_procs_cmyk8(dev);
1893
1894
0
    set_dev_proc(dev, output_page, gdev_prn_bg_output_page);
1895
0
}
1896
1897
void gdev_prn_initialize_device_procs_cmyk16(gx_device *dev)
1898
0
{
1899
0
    gdev_prn_initialize_device_procs(dev);
1900
1901
0
    set_dev_proc(dev, map_cmyk_color, cmyk_16bit_map_cmyk_color);
1902
0
    set_dev_proc(dev, map_color_rgb, cmyk_16bit_map_color_rgb);
1903
0
    set_dev_proc(dev, encode_color, cmyk_16bit_map_cmyk_color);
1904
0
    set_dev_proc(dev, decode_color, cmyk_16bit_map_color_cmyk);
1905
0
}
1906
1907
void gdev_prn_initialize_device_procs_cmyk16_bg(gx_device *dev)
1908
0
{
1909
0
    gdev_prn_initialize_device_procs_cmyk16(dev);
1910
1911
0
    set_dev_proc(dev, output_page, gdev_prn_bg_output_page);
1912
0
}