Coverage Report

Created: 2025-06-10 06:56

/src/ghostpdl/psi/zdevice.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
/* Device-related operators */
18
#include "string_.h"
19
#include "ghost.h"
20
#include "oper.h"
21
#include "ialloc.h"
22
#include "idict.h"
23
#include "igstate.h"
24
#include "imain.h"
25
#include "imemory.h"
26
#include "iname.h"
27
#include "interp.h"
28
#include "iparam.h"
29
#include "ivmspace.h"
30
#include "gsmatrix.h"
31
#include "gsstate.h"
32
#include "gxdevice.h"
33
#include "gxalloc.h"
34
#include "gxgetbit.h"
35
#include "store.h"
36
#include "gsicc_manage.h"
37
#include "gxdevsop.h"
38
39
struct_proc_finalize(psi_device_ref_finalize);
40
41
static
42
83.2k
ENUM_PTRS_WITH(psi_device_ref_enum_ptrs, psi_device_ref *devref)
43
7.64k
      {
44
7.64k
          return 0;
45
0
      }
46
75.6k
    case 0:
47
75.6k
      {
48
75.6k
          if (devref->device != NULL && devref->device->memory != NULL) {
49
7.64k
              ENUM_RETURN(gx_device_enum_ptr(devref->device));
50
7.64k
          }
51
67.9k
          return 0;
52
75.6k
      }
53
83.2k
ENUM_PTRS_END
54
55
static
56
75.6k
RELOC_PTRS_WITH(psi_device_ref_reloc_ptrs, psi_device_ref *devref)
57
75.6k
    if (devref->device != NULL && devref->device->memory != NULL) {
58
7.64k
        devref->device = gx_device_reloc_ptr(devref->device, gcst);
59
7.64k
    }
60
75.6k
RELOC_PTRS_END
61
62
gs_private_st_composite_use_final(st_psi_device_ref, psi_device_ref, "psi_device_ref_t",
63
                     psi_device_ref_enum_ptrs, psi_device_ref_reloc_ptrs, psi_device_ref_finalize);
64
65
void
66
psi_device_ref_finalize(const gs_memory_t *cmem, void *vptr)
67
146k
{
68
146k
    psi_device_ref *pdref = (psi_device_ref *)vptr;
69
146k
    (void)cmem;
70
71
    /* pdref->device->memory == NULL indicates either a device prototype
72
       or a device allocated on the stack rather than the heap
73
     */
74
146k
    if (pdref->device != NULL && pdref->device->memory != NULL)
75
146k
        rc_decrement(pdref->device, "psi_device_ref_finalize");
76
77
146k
    pdref->device = NULL;
78
146k
}
79
80
/* <device> <keep_open> .copydevice2 <newdevice> */
81
static int
82
zcopydevice2(i_ctx_t *i_ctx_p)
83
3.56k
{
84
3.56k
    os_ptr op = osp;
85
3.56k
    gx_device *new_dev;
86
3.56k
    int code;
87
3.56k
    psi_device_ref *psdev;
88
89
3.56k
    check_op(2);
90
3.56k
    check_read_type(op[-1], t_device);
91
3.56k
    check_type(*op, t_boolean);
92
3.56k
    if (op[-1].value.pdevice == NULL)
93
        /* This can happen if we invalidated devices on the stack by calling nulldevice after they were pushed */
94
0
        return_error(gs_error_undefined);
95
96
3.56k
    if (gs_is_path_control_active((const gs_memory_t *)i_ctx_p->memory.current)) {
97
0
        const gx_device *dev = (const gx_device *)op[-1].value.pdevice->device;
98
99
0
        if (gs_check_device_permission((gs_memory_t *)i_ctx_p->memory.current, dev->dname, strlen(dev->dname)) == 0)
100
0
            return_error(gs_error_invalidaccess);
101
0
    }
102
103
3.56k
    code = gs_copydevice2(&new_dev, op[-1].value.pdevice->device, op->value.boolval,
104
3.56k
                          imemory);
105
3.56k
    if (code < 0)
106
0
        return code;
107
3.56k
    new_dev->memory = imemory;
108
109
3.56k
    psdev = gs_alloc_struct(imemory, psi_device_ref, &st_psi_device_ref, "zcopydevice2");
110
3.56k
    if (!psdev) {
111
0
        rc_decrement(new_dev, "zcopydevice2");
112
0
        return_error(gs_error_VMerror);
113
0
    }
114
3.56k
    psdev->device = new_dev;
115
116
3.56k
    make_tav(op - 1, t_device, icurrent_space | a_all, pdevice, psdev);
117
3.56k
    pop(1);
118
3.56k
    return 0;
119
3.56k
}
120
121
/* - currentdevice <device> */
122
/* Returns the current device in the graphics state */
123
int
124
zcurrentdevice(i_ctx_t *i_ctx_p)
125
58.9k
{
126
58.9k
    os_ptr op = osp;
127
58.9k
    gx_device *dev = gs_currentdevice(igs);
128
58.9k
    gs_ref_memory_t *mem = (gs_ref_memory_t *) dev->memory;
129
58.9k
    psi_device_ref *psdev;
130
131
58.9k
    psdev = gs_alloc_struct(dev->memory, psi_device_ref, &st_psi_device_ref, "zcurrentdevice");
132
58.9k
    if (!psdev) {
133
0
        return_error(gs_error_VMerror);
134
0
    }
135
58.9k
    psdev->device = dev;
136
58.9k
    rc_increment(dev);
137
138
58.9k
    push(1);
139
58.9k
    make_tav(op, t_device, imemory_space(mem) | a_all, pdevice, psdev);
140
58.9k
    return 0;
141
58.9k
}
142
143
/* - .currentoutputdevice <device> */
144
/* Returns the *output* device - which will often
145
   be the same as above, but not always: if a compositor
146
   or other forwarding device, or subclassing device is
147
   in force, that will be referenced by the graphics state
148
   rather than the output device.
149
   This is equivalent of currentdevice device, but returns
150
   the *device* object, rather than the dictionary describing
151
   the device and device state.
152
 */
153
int
154
zcurrentoutputdevice(i_ctx_t *i_ctx_p)
155
8.59k
{
156
8.59k
    os_ptr op = osp;
157
8.59k
    gx_device *odev = NULL, *dev = gs_currentdevice(igs);
158
8.59k
    psi_device_ref *psdev;
159
8.59k
    gs_ref_memory_t *mem = (gs_ref_memory_t *) dev->memory;
160
8.59k
    int code = dev_proc(dev, dev_spec_op)(dev,
161
8.59k
                        gxdso_current_output_device, (void *)&odev, 0);
162
8.59k
    if (code < 0)
163
0
        return code;
164
165
8.59k
    psdev = gs_alloc_struct(dev->memory, psi_device_ref, &st_psi_device_ref, "zcurrentdevice");
166
8.59k
    if (!psdev) {
167
0
        return_error(gs_error_VMerror);
168
0
    }
169
8.59k
    psdev->device = odev;
170
8.59k
    rc_increment(odev);
171
172
8.59k
    push(1);
173
8.59k
    make_tav(op, t_device, imemory_space(mem) | a_all, pdevice, psdev);
174
8.59k
    return 0;
175
8.59k
}
176
177
/* <device> .devicename <string> */
178
static int
179
zdevicename(i_ctx_t *i_ctx_p)
180
83.5k
{
181
83.5k
    os_ptr op = osp;
182
83.5k
    const char *dname;
183
184
83.5k
    check_op(1);
185
83.5k
    check_read_type(*op, t_device);
186
83.5k
    if (op->value.pdevice == NULL)
187
        /* This can happen if we invalidated devices on the stack by calling nulldevice after they were pushed */
188
0
        return_error(gs_error_undefined);
189
190
83.5k
    dname = op->value.pdevice->device->dname;
191
83.5k
    make_const_string(op, avm_foreign | a_readonly, strlen(dname),
192
83.5k
                      (const byte *)dname);
193
83.5k
    return 0;
194
83.5k
}
195
196
/* - .doneshowpage - */
197
static int
198
zdoneshowpage(i_ctx_t *i_ctx_p)
199
3.46k
{
200
3.46k
    gx_device *dev = gs_currentdevice(igs);
201
3.46k
    gx_device *tdev = (*dev_proc(dev, get_page_device)) (dev);
202
203
3.46k
    if (tdev != 0)
204
3.46k
        tdev->ShowpageCount++;
205
3.46k
    return 0;
206
3.46k
}
207
208
/* - flushpage - */
209
int
210
zflushpage(i_ctx_t *i_ctx_p)
211
1.78k
{
212
1.78k
    return gs_flushpage(igs);
213
1.78k
}
214
215
/* <device> <x> <y> <width> <max_height> <alpha?> <std_depth|null> <string> */
216
/*   .getbitsrect <height> <substring> */
217
static int
218
zgetbitsrect(i_ctx_t *i_ctx_p)
219
0
{ /*
220
         * alpha? is 0 for no alpha, -1 for alpha first, 1 for alpha last.
221
         * std_depth is null for native pixels, depth/component for
222
         * standard color space.
223
         */
224
0
    os_ptr op = osp;
225
0
    gx_device *dev;
226
0
    gs_int_rect rect;
227
0
    gs_get_bits_params_t params;
228
0
    int w, h;
229
0
    gs_get_bits_options_t options =
230
0
        GB_ALIGN_ANY | GB_RETURN_COPY | GB_OFFSET_0 | GB_RASTER_STANDARD |
231
0
        GB_PACKING_CHUNKY;
232
0
    int depth;
233
0
    uint raster;
234
0
    int num_rows;
235
0
    int code;
236
237
0
    check_op(7);
238
0
    check_read_type(op[-7], t_device);
239
0
    if (op[-7].value.pdevice == NULL)
240
        /* This can happen if we invalidated devices on the stack by calling nulldevice after they were pushed */
241
0
        return_error(gs_error_undefined);
242
243
0
    dev = op[-7].value.pdevice->device;
244
245
0
    check_int_leu(op[-6], dev->width);
246
0
    rect.p.x = op[-6].value.intval;
247
0
    check_int_leu(op[-5], dev->height);
248
0
    rect.p.y = op[-5].value.intval;
249
0
    check_int_leu(op[-4], dev->width);
250
0
    w = op[-4].value.intval;
251
0
    check_int_leu(op[-3], dev->height);
252
0
    h = op[-3].value.intval;
253
0
    check_type(op[-2], t_integer);
254
    /*
255
     * We use if/else rather than switch because the value is long,
256
     * which is not supported as a switch value in pre-ANSI C.
257
     */
258
0
    if (op[-2].value.intval == -1)
259
0
        options |= GB_ALPHA_FIRST;
260
0
    else if (op[-2].value.intval == 0)
261
0
        options |= GB_ALPHA_NONE;
262
0
    else if (op[-2].value.intval == 1)
263
0
        options |= GB_ALPHA_LAST;
264
0
    else
265
0
        return_error(gs_error_rangecheck);
266
0
    if (r_has_type(op - 1, t_null)) {
267
0
        options |= GB_COLORS_NATIVE;
268
0
        depth = dev->color_info.depth;
269
0
    } else {
270
0
        static const gs_get_bits_options_t depths[17] = {
271
0
            0, GB_DEPTH_1, GB_DEPTH_2, 0, GB_DEPTH_4, 0, 0, 0, GB_DEPTH_8,
272
0
            0, 0, 0, GB_DEPTH_12, 0, 0, 0, GB_DEPTH_16
273
0
        };
274
0
        gs_get_bits_options_t depth_option;
275
0
        int std_depth;
276
277
0
        check_int_leu(op[-1], 16);
278
0
        std_depth = (int)op[-1].value.intval;
279
0
        depth_option = depths[std_depth];
280
0
        if (depth_option == 0)
281
0
            return_error(gs_error_rangecheck);
282
0
        options |= depth_option | GB_COLORS_NATIVE;
283
0
        depth = (dev->color_info.num_components +
284
0
                 (options & GB_ALPHA_NONE ? 0 : 1)) * std_depth;
285
0
    }
286
0
    if (w == 0)
287
0
        return_error(gs_error_rangecheck);
288
0
    raster = (w * depth + 7) >> 3;
289
0
    check_write_type(*op, t_string);
290
0
    num_rows = r_size(op) / raster;
291
0
    h = min(h, num_rows);
292
0
    if (h == 0)
293
0
        return_error(gs_error_rangecheck);
294
0
    rect.q.x = rect.p.x + w;
295
0
    rect.q.y = rect.p.y + h;
296
0
    params.options = options;
297
0
    params.data[0] = op->value.bytes;
298
0
    code = (*dev_proc(dev, get_bits_rectangle))(dev, &rect, &params);
299
0
    if (code < 0)
300
0
        return code;
301
0
    make_int(op - 7, h);
302
0
    op[-6] = *op;
303
0
    r_set_size(op - 6, h * raster);
304
0
    pop(6);
305
0
    return 0;
306
0
}
307
308
/* <int> .getdevice <device> */
309
static int
310
zgetdevice(i_ctx_t *i_ctx_p)
311
78.4k
{
312
78.4k
    os_ptr op = osp;
313
78.4k
    const gx_device *dev;
314
78.4k
    psi_device_ref *psdev;
315
316
78.4k
    check_op(1);
317
78.4k
    check_type(*op, t_integer);
318
78.4k
    if (op->value.intval != (int)(op->value.intval))
319
0
        return_error(gs_error_rangecheck);  /* won't fit in an int */
320
78.4k
    dev = gs_getdevice((int)(op->value.intval));
321
78.4k
    if (dev == 0)    /* index out of range */
322
3.56k
        return_error(gs_error_rangecheck);
323
324
74.9k
    psdev = gs_alloc_struct(imemory, psi_device_ref, &st_psi_device_ref, "zgetdevice");
325
74.9k
    if (!psdev) {
326
0
        return_error(gs_error_VMerror);
327
0
    }
328
    /* gs_getdevice() returns a device prototype, so no reference counting required */
329
74.9k
    psdev->device = (gx_device *)dev;
330
331
    /* Device prototypes are read-only; */
332
74.9k
    make_tav(op, t_device, imemory_space(iimemory) | a_readonly, pdevice, psdev);
333
74.9k
    return 0;
334
74.9k
}
335
336
/* - .getdefaultdevice <device> */
337
static int
338
zgetdefaultdevice(i_ctx_t *i_ctx_p)
339
0
{
340
0
    os_ptr op = osp;
341
0
    const gx_device *dev;
342
0
    psi_device_ref *psdev;
343
344
0
    dev = gs_getdefaultlibdevice(imemory);
345
0
    if (dev == 0) /* couldn't find a default device */
346
0
        return_error(gs_error_unknownerror);
347
348
0
    psdev = gs_alloc_struct(imemory, psi_device_ref, &st_psi_device_ref, "zgetdefaultdevice");
349
0
    if (!psdev) {
350
0
        return_error(gs_error_VMerror);
351
0
    }
352
    /* gs_getdefaultlibdevice() returns a device prototype, so no reference counting required */
353
0
    psdev->device = (gx_device *)dev;
354
355
0
    push(1);
356
0
    make_tav(op, t_device, imemory_space(iimemory) | a_readonly, pdevice, psdev);
357
0
    return 0;
358
0
}
359
360
/* Common functionality of zgethardwareparms & zgetdeviceparams */
361
static int
362
zget_device_params(i_ctx_t *i_ctx_p, bool is_hardware)
363
51.9k
{
364
51.9k
    os_ptr op = osp;
365
51.9k
    ref rkeys;
366
51.9k
    gx_device *dev;
367
51.9k
    stack_param_list list;
368
51.9k
    int code;
369
51.9k
    ref *pmark;
370
371
51.9k
    check_op(2);
372
51.9k
    check_read_type(op[-1], t_device);
373
374
51.9k
    if(!r_has_type(op, t_null)) {
375
46.5k
        check_type(*op, t_dictionary);
376
46.5k
    }
377
51.9k
    rkeys = *op;
378
51.9k
    if (op[-1].value.pdevice == NULL)
379
        /* This can happen if we invalidated devices on the stack by calling nulldevice after they were pushed */
380
0
        return_error(gs_error_undefined);
381
382
51.9k
    dev = op[-1].value.pdevice->device;
383
384
51.9k
    ref_stack_pop(&o_stack, 1);
385
51.9k
    stack_param_list_write(&list, &o_stack, &rkeys, iimemory);
386
51.9k
    code = gs_get_device_or_hardware_params(dev, (gs_param_list *) & list,
387
51.9k
                                            is_hardware);
388
51.9k
    if (code < 0) {
389
        /* We have to put back the top argument. */
390
0
        if (list.count > 0)
391
0
            ref_stack_pop(&o_stack, list.count * 2 - 1);
392
0
        else {
393
0
            code = ref_stack_push(&o_stack, 1);
394
0
            if (code < 0)
395
0
                return code;
396
0
        }
397
0
        *osp = rkeys;
398
0
        return code;
399
0
    }
400
51.9k
    pmark = ref_stack_index(&o_stack, list.count * 2);
401
51.9k
    if (pmark == NULL)
402
0
        return_error(gs_error_stackunderflow);
403
51.9k
    make_mark(pmark);
404
51.9k
    return 0;
405
51.9k
}
406
/* <device> <key_dict|null> .getdeviceparams <mark> <name> <value> ... */
407
static int
408
zgetdeviceparams(i_ctx_t *i_ctx_p)
409
51.9k
{
410
51.9k
    return zget_device_params(i_ctx_p, false);
411
51.9k
}
412
/* <device> <key_dict|null> .gethardwareparams <mark> <name> <value> ... */
413
static int
414
zgethardwareparams(i_ctx_t *i_ctx_p)
415
0
{
416
0
    return zget_device_params(i_ctx_p, true);
417
0
}
418
419
/* <matrix> <width> <height> <palette> <word?> makewordimagedevice <device> */
420
static int
421
zmakewordimagedevice(i_ctx_t *i_ctx_p)
422
0
{
423
0
    os_ptr op = osp;
424
0
    os_ptr op1 = op - 1;
425
0
    gs_matrix imat;
426
0
    gx_device *new_dev;
427
0
    const byte *colors;
428
0
    int colors_size;
429
0
    int code;
430
0
    psi_device_ref *psdev;
431
432
0
    check_op(5);
433
0
    check_int_leu(op[-3], max_uint >> 1); /* width */
434
0
    check_int_leu(op[-2], max_uint >> 1); /* height */
435
0
    check_type(*op, t_boolean);
436
0
    if (r_has_type(op1, t_null)) { /* true color */
437
0
        colors = 0;
438
0
        colors_size = -24;  /* 24-bit true color */
439
0
    } else if (r_has_type(op1, t_integer)) {
440
        /*
441
         * We use if/else rather than switch because the value is long,
442
         * which is not supported as a switch value in pre-ANSI C.
443
         */
444
0
        if (op1->value.intval != 16 && op1->value.intval != 24 &&
445
0
            op1->value.intval != 32
446
0
            )
447
0
            return_error(gs_error_rangecheck);
448
0
        colors = 0;
449
0
        colors_size = -op1->value.intval;
450
0
    } else {
451
0
        check_type(*op1, t_string); /* palette */
452
0
        if (r_size(op1) > 3 * 256)
453
0
            return_error(gs_error_rangecheck);
454
0
        colors = op1->value.bytes;
455
0
        colors_size = r_size(op1);
456
0
    }
457
0
    if ((code = read_matrix(imemory, op - 4, &imat)) < 0)
458
0
        return code;
459
    /* Everything OK, create device */
460
0
    code = gs_makewordimagedevice(&new_dev, &imat,
461
0
                                  (int)op[-3].value.intval,
462
0
                                  (int)op[-2].value.intval,
463
0
                                  colors, colors_size,
464
0
                                  op->value.boolval, true, imemory);
465
0
    if (code == 0) {
466
0
        new_dev->memory = imemory;
467
468
0
        psdev = gs_alloc_struct(imemory, psi_device_ref, &st_psi_device_ref, "zcurrentdevice");
469
0
        if (!psdev) {
470
0
            rc_decrement(new_dev, "zmakewordimagedevice");
471
0
            return_error(gs_error_VMerror);
472
0
        }
473
0
        psdev->device = new_dev;
474
0
        rc_increment(new_dev);
475
0
        make_tav(op - 4, t_device, imemory_space(iimemory) | a_all, pdevice, psdev);
476
0
        pop(4);
477
0
    }
478
0
    return code;
479
0
}
480
481
/* - nulldevice - */
482
/* Note that nulldevice clears the current pagedevice. */
483
static int
484
znulldevice(i_ctx_t *i_ctx_p)
485
3.38k
{
486
3.38k
    int code = gs_nulldevice(igs);
487
3.38k
    clear_pagedevice(istate);
488
3.38k
    return code;
489
3.38k
}
490
491
extern void print_resource_usage(const gs_main_instance *, gs_dual_memory_t *,
492
                     const char *);
493
494
/* <num_copies> <flush_bool> .outputpage - */
495
static int
496
zoutputpage(i_ctx_t *i_ctx_p)
497
3.46k
{
498
3.46k
    os_ptr op = osp;
499
3.46k
    int code;
500
501
3.46k
    check_op(2);
502
3.46k
    check_type(op[-1], t_integer);
503
3.46k
    check_type(*op, t_boolean);
504
3.46k
    if (gs_debug[':']) {
505
0
        gs_main_instance *minst = get_minst_from_memory((gs_memory_t *)i_ctx_p->memory.current->non_gc_memory);
506
507
0
        print_resource_usage(minst, &(i_ctx_p->memory), "Outputpage start");
508
0
    }
509
3.46k
    code = gs_output_page(igs, (int)op[-1].value.intval,
510
3.46k
                          op->value.boolval);
511
3.46k
    if (code < 0)
512
3.46k
        return code;
513
0
    pop(2);
514
0
    if (gs_debug[':']) {
515
0
        gs_main_instance *minst = get_minst_from_memory((gs_memory_t *)i_ctx_p->memory.current->non_gc_memory);
516
517
0
        print_resource_usage(minst, &(i_ctx_p->memory), "Outputpage end");
518
0
    }
519
0
    return 0;
520
3.46k
}
521
522
/* <device> <policy_dict|null> <require_all> <mark> <name> <value> ... */
523
/*      .putdeviceparams */
524
/*   (on success) <device> <eraseflag> */
525
/*   (on failure) <device> <policy_dict|null> <require_all> <mark> */
526
/*       <name1> <error1> ... */
527
/* For a key that simply was not recognized, if require_all is true, */
528
/* the result will be an /undefined error; if require_all is false, */
529
/* the key will be ignored. */
530
/* Note that .putdeviceparams clears the current pagedevice. */
531
static int
532
zputdeviceparams(i_ctx_t *i_ctx_p)
533
17.7k
{
534
17.7k
    uint count = ref_stack_counttomark(&o_stack);
535
17.7k
    ref *prequire_all;
536
17.7k
    ref *ppolicy;
537
17.7k
    ref *pdev;
538
17.7k
    gx_device *dev;
539
17.7k
    stack_param_list list;
540
17.7k
    int code;
541
17.7k
    int old_width, old_height;
542
17.7k
    int i, dest;
543
544
17.7k
    if (count == 0)
545
0
        return_error(gs_error_unmatchedmark);
546
17.7k
    prequire_all = ref_stack_index(&o_stack, count);
547
17.7k
    if (prequire_all == NULL)
548
0
        return_error(gs_error_stackunderflow);
549
17.7k
    ppolicy = ref_stack_index(&o_stack, count + 1);
550
17.7k
    if (ppolicy == NULL)
551
0
        return_error(gs_error_stackunderflow);
552
17.7k
    pdev = ref_stack_index(&o_stack, count + 2);
553
17.7k
    if (pdev == NULL)
554
0
        return_error(gs_error_stackunderflow);
555
17.7k
    check_type_only(*prequire_all, t_boolean);
556
17.7k
    check_write_type_only(*pdev, t_device);
557
17.7k
    dev = pdev->value.pdevice->device;
558
17.7k
    if (dev == NULL)
559
        /* This can happen if we invalidated devices on the stack by calling nulldevice after they were pushed */
560
0
        return_error(gs_error_undefined);
561
17.7k
    code = stack_param_list_read(&list, &o_stack, 0, ppolicy,
562
17.7k
                                 prequire_all->value.boolval, iimemory);
563
17.7k
    if (code < 0)
564
0
        return code;
565
17.7k
    old_width = dev->width;
566
17.7k
    old_height = dev->height;
567
17.7k
    code = gs_putdeviceparams(dev, (gs_param_list *) & list);
568
    /* Check for names that were undefined or caused errors. */
569
327k
    for (dest = count - 2, i = 0; i < count >> 1; i++) {
570
309k
        ref *o;
571
309k
        if (list.results[i] < 0) {
572
2
            o = ref_stack_index(&o_stack, dest);
573
2
            if (o == NULL)
574
0
                continue;
575
2
            *o = *ref_stack_index(&o_stack, count - (i << 1) - 2);
576
2
            o = ref_stack_index(&o_stack, dest - 1);
577
2
            if (o == NULL)
578
0
                continue;
579
2
            gs_errorname(i_ctx_p, list.results[i], o);
580
2
            dest -= 2;
581
2
        }
582
309k
    }
583
17.7k
    iparam_list_release(&list);
584
17.7k
    if (code < 0) {   /* There were errors reported. */
585
2
        ref_stack_pop(&o_stack, dest + 1);
586
2
        return (code == gs_error_Fatal) ? code : 0; /* cannot continue from Fatal */
587
2
    }
588
17.7k
    if (code > 0 || (code == 0 && (dev->width != old_width || dev->height != old_height))) {
589
        /*
590
         * The device was open and is now closed, or its dimensions have
591
         * changed.  If it was the current device, call setdevice to
592
         * reinstall it and erase the page.
593
         */
594
        /****** DOESN'T FIND ALL THE GSTATES THAT REFERENCE THE DEVICE. ******/
595
6.09k
        if (gs_currentdevice(igs) == dev) {
596
4.30k
            bool was_open = dev->is_open;
597
598
4.30k
            code = gs_setdevice_no_erase(igs, dev);
599
            /* If the device wasn't closed, setdevice won't erase the page. */
600
4.30k
            if (was_open && code >= 0)
601
1.10k
                code = 1;
602
4.30k
        }
603
6.09k
    }
604
17.7k
    if (code < 0)
605
0
        return code;
606
17.7k
    ref_stack_pop(&o_stack, count + 1);
607
17.7k
    make_bool(osp, code);
608
17.7k
    clear_pagedevice(istate);
609
17.7k
    return 0;
610
17.7k
}
611
612
int
613
zsetdevice_no_safer(i_ctx_t *i_ctx_p, gx_device *new_dev)
614
10.3k
{
615
10.3k
    int code;
616
617
10.3k
    if (new_dev == NULL)
618
0
        return gs_note_error(gs_error_undefined);
619
620
10.3k
    code = gs_setdevice_no_erase(igs, new_dev);
621
10.3k
    if (code < 0)
622
0
        return code;
623
624
10.3k
    clear_pagedevice(istate);
625
10.3k
    return code;
626
10.3k
}
627
628
/* <device> .setdevice <eraseflag> */
629
/* Note that .setdevice clears the current pagedevice. */
630
int
631
zsetdevice(i_ctx_t *i_ctx_p)
632
10.3k
{
633
10.3k
    gx_device *odev = NULL, *dev = gs_currentdevice(igs);
634
10.3k
    gx_device *ndev = NULL;
635
10.3k
    os_ptr op = osp;
636
10.3k
    int code = dev_proc(dev, dev_spec_op)(dev,
637
10.3k
                        gxdso_current_output_device, (void *)&odev, 0);
638
639
10.3k
    if (code < 0)
640
0
        return code;
641
10.3k
    check_op(1);
642
10.3k
    check_write_type(*op, t_device);
643
644
10.3k
    if (op->value.pdevice == 0)
645
0
        return gs_note_error(gs_error_undefined);
646
647
    /* slightly icky special case: the new device may not have had
648
     * it's procs initialised, at this point - but we need to check
649
     * whether we're being asked to change the device here
650
     */
651
10.3k
    if (dev_proc((op->value.pdevice->device), dev_spec_op) == NULL)
652
0
        ndev = op->value.pdevice->device;
653
10.3k
    else
654
10.3k
        code = dev_proc((op->value.pdevice->device), dev_spec_op)(op->value.pdevice->device,
655
10.3k
                        gxdso_current_output_device, (void *)&ndev, 0);
656
657
10.3k
    if (code < 0)
658
0
        return code;
659
660
10.3k
    if (odev->LockSafetyParams) {   /* do additional checking if locked  */
661
0
        if(ndev != odev)     /* don't allow a different device    */
662
0
            return_error(gs_error_invalidaccess);
663
0
    }
664
10.3k
    code = zsetdevice_no_safer(i_ctx_p, op->value.pdevice->device);
665
10.3k
    make_bool(op, code != 0);  /* erase page if 1 */
666
10.3k
    return code;
667
10.3k
}
668
669
/* Custom PostScript operator '.special_op' is used to implement
670
 * 'dev_spec_op' access from PostScript. Initially this is intended
671
 * to be used to recover individual device parameters from certain
672
 * devices (pdfwrite, ps2write etc). In the future we may choose to
673
 * increase the devices which can support this, and make more types
674
 * of 'spec_op' available from the PostScript world.
675
 */
676
677
/* We use this structure in a table below which allows us to add new
678
 * 'spec_op's with minimum fuss.
679
 */
680
typedef struct spec_op_s spec_op_t;
681
struct spec_op_s {
682
    char *name;         /* C string representing the name of the spec_op */
683
    int spec_op;                /* Integer used to switch on the name */
684
};
685
686
/* To add more spec_ops, put a key name (used to identify the specific
687
 * spec_op required) in this table, the integer is just used in the switch
688
 * in the main code to execute the required spec_op code.
689
 */
690
spec_op_t spec_op_defs[] = {
691
    {(char *)"GetDeviceParam", 0},
692
    {(char *)"EventInfo", 1},
693
    {(char *)"SupportsDevn", 2},
694
};
695
696
/* <any> <any> .... /spec_op name .special_op <any> <any> .....
697
 * The special_op operator takes at a minimum the name of the spec_op to execute
698
 * and as many additional parameters as are required for the spec_op. It may
699
 * return as many additional parameters as required.
700
 */
701
int
702
zspec_op(i_ctx_t *i_ctx_p)
703
57.3k
{
704
57.3k
    os_ptr  op = osp;
705
57.3k
    gx_device *dev = gs_currentdevice(igs);
706
57.3k
    int i, nprocs = sizeof(spec_op_defs) / sizeof(spec_op_t), code, proc = -1;
707
57.3k
    ref opname, nref, namestr;
708
57.3k
    char *data;
709
710
    /* At the very minimum we need a name object telling us which sepc_op to perform */
711
57.3k
    check_op(1);
712
57.3k
    if (!r_has_type(op, t_name))
713
0
        return_error(gs_error_typecheck);
714
715
57.3k
    ref_assign(&opname, op);
716
717
    /* Find the relevant spec_op name */
718
57.3k
    for (i=0;i<nprocs;i++) {
719
57.3k
        code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)spec_op_defs[i].name, strlen(spec_op_defs[i].name), &nref, 0);
720
57.3k
        if (code < 0)
721
0
            return code;
722
57.3k
        if (name_eq(&opname, &nref)) {
723
57.3k
            proc = i;
724
57.3k
            break;
725
57.3k
        }
726
57.3k
    }
727
728
57.3k
    if (proc < 0)
729
0
        return_error(gs_error_undefined);
730
731
57.3k
    ref_stack_pop(&o_stack, 1);     /* We don't need the name of the spec_op any more */
732
57.3k
    op = osp;
733
734
57.3k
    switch(proc) {
735
57.3k
        case 0:
736
57.3k
            {
737
57.3k
                stack_param_list list;
738
57.3k
                dev_param_req_t request;
739
57.3k
                ref rkeys;
740
                /* Get a single device parameter, we should be supplied with
741
                 * the name of the paramter, as a name object.
742
                 */
743
57.3k
                check_op(1);
744
57.3k
                if (!r_has_type(op, t_name))
745
0
                    return_error(gs_error_typecheck);
746
747
57.3k
                ref_assign(&opname, op);
748
57.3k
                name_string_ref(imemory, &opname, &namestr);
749
750
57.3k
                data = (char *)gs_alloc_bytes(imemory, r_size(&namestr) + 1, "temporary special_op string");
751
57.3k
                if (data == 0)
752
0
                    return_error(gs_error_VMerror);
753
57.3k
                memset(data, 0x00, r_size(&namestr) + 1);
754
57.3k
                memcpy(data, namestr.value.bytes, r_size(&namestr));
755
756
                /* Discard the parameter name now, we're done with it */
757
57.3k
                pop (1);
758
                /* Make a null object so that the stack param list won't check for requests */
759
57.3k
                make_null(&rkeys);
760
57.3k
                stack_param_list_write(&list, &o_stack, &rkeys, iimemory);
761
                /* Stuff the data into a structure for passing to the spec_op */
762
57.3k
                request.Param = data;
763
57.3k
                request.list = &list;
764
765
57.3k
                code = dev_proc(dev, dev_spec_op)(dev, gxdso_get_dev_param, &request, sizeof(dev_param_req_t));
766
767
57.3k
                gs_free_object(imemory, data, "temporary special_op string");
768
769
57.3k
                if (code < 0) {
770
51.9k
                    if (code == gs_error_undefined) {
771
51.9k
                        op = osp;
772
51.9k
                        push(1);
773
51.9k
                        make_bool(op, 0);
774
51.9k
                    } else
775
0
                        return_error(code);
776
51.9k
                } else {
777
5.35k
                    op = osp;
778
5.35k
                    push(1);
779
5.35k
                    make_bool(op, 1);
780
5.35k
                }
781
57.3k
            }
782
57.3k
            break;
783
57.3k
        case 1:
784
0
            {
785
0
                stack_param_list list;
786
0
                dev_param_req_t request;
787
0
                ref rkeys;
788
                /* EventInfo we should be supplied with a name object which we
789
                 * pass as the event info to the dev_spec_op
790
                 */
791
0
                check_op(1);
792
0
                if (!r_has_type(op, t_name))
793
0
                    return_error(gs_error_typecheck);
794
795
0
                ref_assign(&opname, op);
796
0
                name_string_ref(imemory, &opname, &namestr);
797
798
0
                data = (char *)gs_alloc_bytes(imemory, r_size(&namestr) + 1, "temporary special_op string");
799
0
                if (data == 0)
800
0
                    return_error(gs_error_VMerror);
801
0
                memset(data, 0x00, r_size(&namestr) + 1);
802
0
                memcpy(data, namestr.value.bytes, r_size(&namestr));
803
804
                /* Discard the parameter name now, we're done with it */
805
0
                pop (1);
806
                /* Make a null object so that the stack param list won't check for requests */
807
0
                make_null(&rkeys);
808
0
                stack_param_list_write(&list, &o_stack, &rkeys, iimemory);
809
                /* Stuff the data into a structure for passing to the spec_op */
810
0
                request.Param = data;
811
0
                request.list = &list;
812
813
0
                code = dev_proc(dev, dev_spec_op)(dev, gxdso_event_info, &request, sizeof(dev_param_req_t));
814
815
0
                gs_free_object(imemory, data, "temporary special_op string");
816
817
0
                if (code < 0) {
818
0
                    if (code == gs_error_undefined) {
819
0
                        op = osp;
820
0
                        push(1);
821
0
                        make_bool(op, 0);
822
0
                    } else
823
0
                        return_error(code);
824
0
                }
825
0
            }
826
0
            break;
827
0
        case 2:
828
0
            {
829
                /* SupportsDevn. Return the boolean from the device */
830
831
0
                code = dev_proc(dev, dev_spec_op)(dev, gxdso_supports_devn, NULL, 0);
832
0
                if (code < 0 && code != gs_error_undefined)
833
0
                    return_error(code);   /* any other error leaves the stack unchanged */
834
835
0
                op = osp;
836
0
                push(1);
837
0
                make_bool(op, code > 0 ? 1 : 0); /* return true/false */
838
0
            }
839
0
            break;
840
0
        default:
841
            /* Belt and braces; it shold not be possible to get here, as the table
842
             * containing the names should mirror the entries in this switch. If we
843
             * found a name there should be a matching case here.
844
             */
845
0
            return_error(gs_error_undefined);
846
0
            break;
847
57.3k
    }
848
57.3k
    return 0;
849
57.3k
}
850
851
/* ------ Initialization procedure ------ */
852
853
const op_def zdevice_op_defs[] =
854
{
855
    {"2.copydevice2", zcopydevice2},
856
    {"0currentdevice", zcurrentdevice},
857
    {"0.currentoutputdevice", zcurrentoutputdevice},
858
    {"1.devicename", zdevicename},
859
    {"0.doneshowpage", zdoneshowpage},
860
    {"0flushpage", zflushpage},
861
    {"7.getbitsrect", zgetbitsrect},
862
    {"1.getdevice", zgetdevice},
863
    {"0.getdefaultdevice", zgetdefaultdevice},
864
    {"2.getdeviceparams", zgetdeviceparams},
865
    {"2.gethardwareparams", zgethardwareparams},
866
    {"5makewordimagedevice", zmakewordimagedevice},
867
    {"0nulldevice", znulldevice},
868
    {"2.outputpage", zoutputpage},
869
    {"3.putdeviceparams", zputdeviceparams},
870
    {"1.setdevice", zsetdevice},
871
    op_def_end(0)
872
};
873
874
/* We need to split the table because of the 16-element limit. */
875
const op_def zdevice_ext_op_defs[] =
876
{
877
    {"0.special_op", zspec_op},
878
    op_def_end(0)
879
};