Coverage Report

Created: 2022-10-31 07:00

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