Coverage Report

Created: 2025-06-10 06:58

/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
416k
ENUM_PTRS_WITH(psi_device_ref_enum_ptrs, psi_device_ref *devref)
43
38.3k
      {
44
38.3k
          return 0;
45
0
      }
46
378k
    case 0:
47
378k
      {
48
378k
          if (devref->device != NULL && devref->device->memory != NULL) {
49
38.3k
              ENUM_RETURN(gx_device_enum_ptr(devref->device));
50
38.3k
          }
51
340k
          return 0;
52
378k
      }
53
416k
ENUM_PTRS_END
54
55
static
56
378k
RELOC_PTRS_WITH(psi_device_ref_reloc_ptrs, psi_device_ref *devref)
57
378k
    if (devref->device != NULL && devref->device->memory != NULL) {
58
38.3k
        devref->device = gx_device_reloc_ptr(devref->device, gcst);
59
38.3k
    }
60
378k
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
546k
{
68
546k
    psi_device_ref *pdref = (psi_device_ref *)vptr;
69
546k
    (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
546k
    if (pdref->device != NULL && pdref->device->memory != NULL)
75
546k
        rc_decrement(pdref->device, "psi_device_ref_finalize");
76
77
546k
    pdref->device = NULL;
78
546k
}
79
80
/* <device> <keep_open> .copydevice2 <newdevice> */
81
static int
82
zcopydevice2(i_ctx_t *i_ctx_p)
83
17.7k
{
84
17.7k
    os_ptr op = osp;
85
17.7k
    gx_device *new_dev;
86
17.7k
    int code;
87
17.7k
    psi_device_ref *psdev;
88
89
17.7k
    check_op(2);
90
17.7k
    check_read_type(op[-1], t_device);
91
17.7k
    check_type(*op, t_boolean);
92
17.7k
    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
17.7k
    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
17.7k
    code = gs_copydevice2(&new_dev, op[-1].value.pdevice->device, op->value.boolval,
104
17.7k
                          imemory);
105
17.7k
    if (code < 0)
106
0
        return code;
107
17.7k
    new_dev->memory = imemory;
108
109
17.7k
    psdev = gs_alloc_struct(imemory, psi_device_ref, &st_psi_device_ref, "zcopydevice2");
110
17.7k
    if (!psdev) {
111
0
        rc_decrement(new_dev, "zcopydevice2");
112
0
        return_error(gs_error_VMerror);
113
0
    }
114
17.7k
    psdev->device = new_dev;
115
116
17.7k
    make_tav(op - 1, t_device, icurrent_space | a_all, pdevice, psdev);
117
17.7k
    pop(1);
118
17.7k
    return 0;
119
17.7k
}
120
121
/* - currentdevice <device> */
122
/* Returns the current device in the graphics state */
123
int
124
zcurrentdevice(i_ctx_t *i_ctx_p)
125
137k
{
126
137k
    os_ptr op = osp;
127
137k
    gx_device *dev = gs_currentdevice(igs);
128
137k
    gs_ref_memory_t *mem = (gs_ref_memory_t *) dev->memory;
129
137k
    psi_device_ref *psdev;
130
131
137k
    psdev = gs_alloc_struct(dev->memory, psi_device_ref, &st_psi_device_ref, "zcurrentdevice");
132
137k
    if (!psdev) {
133
0
        return_error(gs_error_VMerror);
134
0
    }
135
137k
    psdev->device = dev;
136
137k
    rc_increment(dev);
137
138
137k
    push(1);
139
137k
    make_tav(op, t_device, imemory_space(mem) | a_all, pdevice, psdev);
140
137k
    return 0;
141
137k
}
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
17.6k
{
156
17.6k
    os_ptr op = osp;
157
17.6k
    gx_device *odev = NULL, *dev = gs_currentdevice(igs);
158
17.6k
    psi_device_ref *psdev;
159
17.6k
    gs_ref_memory_t *mem = (gs_ref_memory_t *) dev->memory;
160
17.6k
    int code = dev_proc(dev, dev_spec_op)(dev,
161
17.6k
                        gxdso_current_output_device, (void *)&odev, 0);
162
17.6k
    if (code < 0)
163
0
        return code;
164
165
17.6k
    psdev = gs_alloc_struct(dev->memory, psi_device_ref, &st_psi_device_ref, "zcurrentdevice");
166
17.6k
    if (!psdev) {
167
0
        return_error(gs_error_VMerror);
168
0
    }
169
17.6k
    psdev->device = odev;
170
17.6k
    rc_increment(odev);
171
172
17.6k
    push(1);
173
17.6k
    make_tav(op, t_device, imemory_space(mem) | a_all, pdevice, psdev);
174
17.6k
    return 0;
175
17.6k
}
176
177
/* <device> .devicename <string> */
178
static int
179
zdevicename(i_ctx_t *i_ctx_p)
180
390k
{
181
390k
    os_ptr op = osp;
182
390k
    const char *dname;
183
184
390k
    check_op(1);
185
390k
    check_read_type(*op, t_device);
186
390k
    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
390k
    dname = op->value.pdevice->device->dname;
191
390k
    make_const_string(op, avm_foreign | a_readonly, strlen(dname),
192
390k
                      (const byte *)dname);
193
390k
    return 0;
194
390k
}
195
196
/* - .doneshowpage - */
197
static int
198
zdoneshowpage(i_ctx_t *i_ctx_p)
199
6.13k
{
200
6.13k
    gx_device *dev = gs_currentdevice(igs);
201
6.13k
    gx_device *tdev = (*dev_proc(dev, get_page_device)) (dev);
202
203
6.13k
    if (tdev != 0)
204
6.13k
        tdev->ShowpageCount++;
205
6.13k
    return 0;
206
6.13k
}
207
208
/* - flushpage - */
209
int
210
zflushpage(i_ctx_t *i_ctx_p)
211
8.88k
{
212
8.88k
    return gs_flushpage(igs);
213
8.88k
}
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
390k
{
312
390k
    os_ptr op = osp;
313
390k
    const gx_device *dev;
314
390k
    psi_device_ref *psdev;
315
316
390k
    check_op(1);
317
390k
    check_type(*op, t_integer);
318
390k
    if (op->value.intval != (int)(op->value.intval))
319
0
        return_error(gs_error_rangecheck);  /* won't fit in an int */
320
390k
    dev = gs_getdevice((int)(op->value.intval));
321
390k
    if (dev == 0)    /* index out of range */
322
17.7k
        return_error(gs_error_rangecheck);
323
324
373k
    psdev = gs_alloc_struct(imemory, psi_device_ref, &st_psi_device_ref, "zgetdevice");
325
373k
    if (!psdev) {
326
0
        return_error(gs_error_VMerror);
327
0
    }
328
    /* gs_getdevice() returns a device prototype, so no reference counting required */
329
373k
    psdev->device = (gx_device *)dev;
330
331
    /* Device prototypes are read-only; */
332
373k
    make_tav(op, t_device, imemory_space(iimemory) | a_readonly, pdevice, psdev);
333
373k
    return 0;
334
373k
}
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
132k
{
364
132k
    os_ptr op = osp;
365
132k
    ref rkeys;
366
132k
    gx_device *dev;
367
132k
    stack_param_list list;
368
132k
    int code;
369
132k
    ref *pmark;
370
371
132k
    check_op(2);
372
132k
    check_read_type(op[-1], t_device);
373
374
132k
    if(!r_has_type(op, t_null)) {
375
105k
        check_type(*op, t_dictionary);
376
105k
    }
377
132k
    rkeys = *op;
378
132k
    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
132k
    dev = op[-1].value.pdevice->device;
383
384
132k
    ref_stack_pop(&o_stack, 1);
385
132k
    stack_param_list_write(&list, &o_stack, &rkeys, iimemory);
386
132k
    code = gs_get_device_or_hardware_params(dev, (gs_param_list *) & list,
387
132k
                                            is_hardware);
388
132k
    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
132k
    pmark = ref_stack_index(&o_stack, list.count * 2);
401
132k
    if (pmark == NULL)
402
0
        return_error(gs_error_stackunderflow);
403
132k
    make_mark(pmark);
404
132k
    return 0;
405
132k
}
406
/* <device> <key_dict|null> .getdeviceparams <mark> <name> <value> ... */
407
static int
408
zgetdeviceparams(i_ctx_t *i_ctx_p)
409
132k
{
410
132k
    return zget_device_params(i_ctx_p, false);
411
132k
}
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
12.7k
{
486
12.7k
    int code = gs_nulldevice(igs);
487
12.7k
    clear_pagedevice(istate);
488
12.7k
    return code;
489
12.7k
}
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
6.13k
{
498
6.13k
    os_ptr op = osp;
499
6.13k
    int code;
500
501
6.13k
    check_op(2);
502
6.13k
    check_type(op[-1], t_integer);
503
6.13k
    check_type(*op, t_boolean);
504
6.13k
    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
6.13k
    code = gs_output_page(igs, (int)op[-1].value.intval,
510
6.13k
                          op->value.boolval);
511
6.13k
    if (code < 0)
512
1.96k
        return code;
513
4.17k
    pop(2);
514
4.17k
    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
4.17k
    return 0;
520
6.13k
}
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
58.7k
{
534
58.7k
    uint count = ref_stack_counttomark(&o_stack);
535
58.7k
    ref *prequire_all;
536
58.7k
    ref *ppolicy;
537
58.7k
    ref *pdev;
538
58.7k
    gx_device *dev;
539
58.7k
    stack_param_list list;
540
58.7k
    int code;
541
58.7k
    int old_width, old_height;
542
58.7k
    int i, dest;
543
544
58.7k
    if (count == 0)
545
0
        return_error(gs_error_unmatchedmark);
546
58.7k
    prequire_all = ref_stack_index(&o_stack, count);
547
58.7k
    if (prequire_all == NULL)
548
0
        return_error(gs_error_stackunderflow);
549
58.7k
    ppolicy = ref_stack_index(&o_stack, count + 1);
550
58.7k
    if (ppolicy == NULL)
551
0
        return_error(gs_error_stackunderflow);
552
58.7k
    pdev = ref_stack_index(&o_stack, count + 2);
553
58.7k
    if (pdev == NULL)
554
0
        return_error(gs_error_stackunderflow);
555
58.7k
    check_type_only(*prequire_all, t_boolean);
556
58.7k
    check_write_type_only(*pdev, t_device);
557
58.7k
    dev = pdev->value.pdevice->device;
558
58.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
58.7k
    code = stack_param_list_read(&list, &o_stack, 0, ppolicy,
562
58.7k
                                 prequire_all->value.boolval, iimemory);
563
58.7k
    if (code < 0)
564
0
        return code;
565
58.7k
    old_width = dev->width;
566
58.7k
    old_height = dev->height;
567
58.7k
    code = gs_putdeviceparams(dev, (gs_param_list *) & list);
568
    /* Check for names that were undefined or caused errors. */
569
1.16M
    for (dest = count - 2, i = 0; i < count >> 1; i++) {
570
1.10M
        ref *o;
571
1.10M
        if (list.results[i] < 0) {
572
18
            o = ref_stack_index(&o_stack, dest);
573
18
            if (o == NULL)
574
0
                continue;
575
18
            *o = *ref_stack_index(&o_stack, count - (i << 1) - 2);
576
18
            o = ref_stack_index(&o_stack, dest - 1);
577
18
            if (o == NULL)
578
0
                continue;
579
18
            gs_errorname(i_ctx_p, list.results[i], o);
580
18
            dest -= 2;
581
18
        }
582
1.10M
    }
583
58.7k
    iparam_list_release(&list);
584
58.7k
    if (code < 0) {   /* There were errors reported. */
585
18
        ref_stack_pop(&o_stack, dest + 1);
586
18
        return (code == gs_error_Fatal) ? code : 0; /* cannot continue from Fatal */
587
18
    }
588
58.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
19.5k
        if (gs_currentdevice(igs) == dev) {
596
10.6k
            bool was_open = dev->is_open;
597
598
10.6k
            code = gs_setdevice_no_erase(igs, dev);
599
            /* If the device wasn't closed, setdevice won't erase the page. */
600
10.6k
            if (was_open && code >= 0)
601
2.87k
                code = 1;
602
10.6k
        }
603
19.5k
    }
604
58.7k
    if (code < 0)
605
0
        return code;
606
58.7k
    ref_stack_pop(&o_stack, count + 1);
607
58.7k
    make_bool(osp, code);
608
58.7k
    clear_pagedevice(istate);
609
58.7k
    return 0;
610
58.7k
}
611
612
int
613
zsetdevice_no_safer(i_ctx_t *i_ctx_p, gx_device *new_dev)
614
26.4k
{
615
26.4k
    int code;
616
617
26.4k
    if (new_dev == NULL)
618
0
        return gs_note_error(gs_error_undefined);
619
620
26.4k
    code = gs_setdevice_no_erase(igs, new_dev);
621
26.4k
    if (code < 0)
622
0
        return code;
623
624
26.4k
    clear_pagedevice(istate);
625
26.4k
    return code;
626
26.4k
}
627
628
/* <device> .setdevice <eraseflag> */
629
/* Note that .setdevice clears the current pagedevice. */
630
int
631
zsetdevice(i_ctx_t *i_ctx_p)
632
26.4k
{
633
26.4k
    gx_device *odev = NULL, *dev = gs_currentdevice(igs);
634
26.4k
    gx_device *ndev = NULL;
635
26.4k
    os_ptr op = osp;
636
26.4k
    int code = dev_proc(dev, dev_spec_op)(dev,
637
26.4k
                        gxdso_current_output_device, (void *)&odev, 0);
638
639
26.4k
    if (code < 0)
640
0
        return code;
641
26.4k
    check_op(1);
642
26.4k
    check_write_type(*op, t_device);
643
644
26.4k
    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
26.4k
    if (dev_proc((op->value.pdevice->device), dev_spec_op) == NULL)
652
0
        ndev = op->value.pdevice->device;
653
26.4k
    else
654
26.4k
        code = dev_proc((op->value.pdevice->device), dev_spec_op)(op->value.pdevice->device,
655
26.4k
                        gxdso_current_output_device, (void *)&ndev, 0);
656
657
26.4k
    if (code < 0)
658
0
        return code;
659
660
26.4k
    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
26.4k
    code = zsetdevice_no_safer(i_ctx_p, op->value.pdevice->device);
665
26.4k
    make_bool(op, code != 0);  /* erase page if 1 */
666
26.4k
    return code;
667
26.4k
}
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
170k
{
704
170k
    os_ptr  op = osp;
705
170k
    gx_device *dev = gs_currentdevice(igs);
706
170k
    int i, nprocs = sizeof(spec_op_defs) / sizeof(spec_op_t), code, proc = -1;
707
170k
    ref opname, nref, namestr;
708
170k
    char *data;
709
710
    /* At the very minimum we need a name object telling us which sepc_op to perform */
711
170k
    check_op(1);
712
170k
    if (!r_has_type(op, t_name))
713
0
        return_error(gs_error_typecheck);
714
715
170k
    ref_assign(&opname, op);
716
717
    /* Find the relevant spec_op name */
718
170k
    for (i=0;i<nprocs;i++) {
719
170k
        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
170k
        if (code < 0)
721
0
            return code;
722
170k
        if (name_eq(&opname, &nref)) {
723
170k
            proc = i;
724
170k
            break;
725
170k
        }
726
170k
    }
727
728
170k
    if (proc < 0)
729
0
        return_error(gs_error_undefined);
730
731
170k
    ref_stack_pop(&o_stack, 1);     /* We don't need the name of the spec_op any more */
732
170k
    op = osp;
733
734
170k
    switch(proc) {
735
170k
        case 0:
736
170k
            {
737
170k
                stack_param_list list;
738
170k
                dev_param_req_t request;
739
170k
                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
170k
                check_op(1);
744
170k
                if (!r_has_type(op, t_name))
745
0
                    return_error(gs_error_typecheck);
746
747
170k
                ref_assign(&opname, op);
748
170k
                name_string_ref(imemory, &opname, &namestr);
749
750
170k
                data = (char *)gs_alloc_bytes(imemory, r_size(&namestr) + 1, "temporary special_op string");
751
170k
                if (data == 0)
752
0
                    return_error(gs_error_VMerror);
753
170k
                memset(data, 0x00, r_size(&namestr) + 1);
754
170k
                memcpy(data, namestr.value.bytes, r_size(&namestr));
755
756
                /* Discard the parameter name now, we're done with it */
757
170k
                pop (1);
758
                /* Make a null object so that the stack param list won't check for requests */
759
170k
                make_null(&rkeys);
760
170k
                stack_param_list_write(&list, &o_stack, &rkeys, iimemory);
761
                /* Stuff the data into a structure for passing to the spec_op */
762
170k
                request.Param = data;
763
170k
                request.list = &list;
764
765
170k
                code = dev_proc(dev, dev_spec_op)(dev, gxdso_get_dev_param, &request, sizeof(dev_param_req_t));
766
767
170k
                gs_free_object(imemory, data, "temporary special_op string");
768
769
170k
                if (code < 0) {
770
143k
                    if (code == gs_error_undefined) {
771
143k
                        op = osp;
772
143k
                        push(1);
773
143k
                        make_bool(op, 0);
774
143k
                    } else
775
0
                        return_error(code);
776
143k
                } else {
777
26.6k
                    op = osp;
778
26.6k
                    push(1);
779
26.6k
                    make_bool(op, 1);
780
26.6k
                }
781
170k
            }
782
170k
            break;
783
170k
        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
170k
    }
848
170k
    return 0;
849
170k
}
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
};