Coverage Report

Created: 2025-11-16 07:40

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