Coverage Report

Created: 2026-04-01 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pcl/pxl/pxtop.c
Line
Count
Source
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
/* pxtop.c */
18
/* Top-level API implementation of PCL/XL */
19
20
#include "stdio_.h"
21
#include "string_.h"
22
#include "gdebug.h"
23
#include "gserrors.h"
24
#include "gstypes.h"
25
#include "gsmemory.h"
26
#include "gsstate.h"            /* must precede gsdevice.h */
27
#include "gsdevice.h"
28
#include "gsstruct.h"           /* for gxalloc.h */
29
#include "gspaint.h"
30
#include "gsfont.h"
31
#include "gxalloc.h"
32
#include "gxstate.h"
33
#include "gxdevice.h"
34
#include "plparse.h"
35
#include "pxattr.h"             /* for pxparse.h */
36
#include "pxerrors.h"
37
#include "pxoper.h"
38
#include "pxstate.h"
39
#include "pxfont.h"
40
#include "pxvalue.h"            /* for pxparse.h */
41
#include "pxparse.h"
42
#include "pxptable.h"
43
#include "pxstate.h"
44
#include "pltop.h"
45
#include "plmain.h"
46
#include "gsicc_manage.h"
47
#include "gxdevsop.h"
48
49
/* Imported operators */
50
px_operator_proc(pxEndPage);
51
px_operator_proc(pxBeginSession);
52
53
/* Forward decls */
54
static int pxl_end_page_top(px_state_t * pxs, int num_copies, int flush);
55
56
static int px_top_init(px_parser_state_t * st, px_state_t * pxs,
57
                       bool big_endian);
58
59
/* ------------ PCXL stream header processor ------- */
60
/* State used to process an XL stream header */
61
typedef struct px_stream_header_process_s
62
{
63
    enum { PSHPReady, PSHPSkipping, PSHPDone } state;
64
    px_parser_state_t *st;      /* parser state to refer to */
65
    px_state_t *pxs;            /* xl state to refer to */
66
} px_stream_header_process_t;
67
68
/* Initialize stream header processor */
69
static void
70
px_stream_header_init(px_stream_header_process_t * process,
71
                      px_parser_state_t * st,
72
                      px_state_t * pxs)
73
4.58k
{
74
4.58k
    process->state = PSHPReady;
75
4.58k
    process->st = st;
76
4.58k
    process->pxs = pxs;
77
4.58k
}
78
79
/* Process stream header input */
80
/* ret -ve error, 0 if needs more input, 1 if done successfully */
81
static int
82
px_stream_header_process(px_stream_header_process_t * process,
83
                         stream_cursor_read * cursor)
84
4.59k
{
85
225k
    while (cursor->ptr != cursor->limit) {
86
225k
        switch (process->state) {
87
4.58k
        case PSHPReady:
88
4.58k
            process->state = PSHPSkipping;  /* switch to next state */
89
4.58k
            switch ((*++cursor->ptr)) {
90
0
            case '(':
91
0
                px_top_init(process->st, process->pxs, true);
92
0
                break;
93
4.57k
            case ')':
94
4.57k
                px_top_init(process->st, process->pxs, false);
95
4.57k
                break;
96
6
            default:
97
                /* Initialize state to avoid confusion */
98
6
                px_top_init(process->st, process->pxs, true);
99
6
                return gs_note_error(errorUnsupportedBinding);
100
4.58k
            }
101
4.57k
            break;
102
221k
        case PSHPSkipping:
103
221k
            if ((*++cursor->ptr) == '\n') {
104
4.53k
                process->state = PSHPDone;
105
4.53k
                return 1;
106
4.53k
            }
107
216k
            break;
108
216k
        case PSHPDone:
109
0
        default:
110
            /* Shouldn't ever come here */
111
0
            return gs_note_error(errorIllegalStreamHeader);
112
225k
        }
113
225k
    }
114
50
    return 0;                   /* need more input */
115
4.59k
}
116
117
/* De-initialize stream header processor */
118
static void
119
px_stream_header_dnit(px_stream_header_process_t * process)
120
4.58k
{
121
    /* empty proc */
122
4.58k
}
123
124
/*
125
 * PXL interpreter instance: derived from pl_interp_implementation_t
126
 */
127
typedef struct pxl_interp_instance_s
128
{
129
    gs_memory_t *memory;        /* memory allocator to use */
130
    px_parser_state_t *st;      /* parser state */
131
    px_state_t *pxs;            /* interp state */
132
    gs_gstate *pgs;             /* graphics state */
133
    enum {
134
        PSHeader,
135
        PSXL,
136
        PSDone
137
    } processState;             /* interp's processing state */
138
    px_stream_header_process_t headerState;        /* used to decode stream header */
139
} pxl_interp_instance_t;
140
141
static int
142
pxl_detect_language(const char *s, int len)
143
17.7k
{
144
17.7k
   if (len < 11)
145
578
       return 0;
146
17.1k
   if (memcmp(s, ") HP-PCL XL", 11) == 0)
147
2.66k
       return 100;
148
14.4k
   return 0;
149
17.1k
}
150
151
/* Get implementation's characteristics */
152
static const pl_interp_characteristics_t *      /* always returns a descriptor */
153
pxl_impl_characteristics(const pl_interp_implementation_t * impl)        /* implementation of interpreter to alloc */
154
39.5k
{
155
    /* version and build date are not currently used */
156
39.5k
#define PXLVERSION NULL
157
39.5k
#define PXLBUILDDATE NULL
158
39.5k
    static pl_interp_characteristics_t pxl_characteristics = {
159
39.5k
        "PCLXL",
160
39.5k
        pxl_detect_language,
161
39.5k
    };
162
39.5k
    return &pxl_characteristics;
163
39.5k
}
164
165
/* Do per-instance interpreter allocation/init. No device is set yet */
166
static int                      /* ret 0 ok, else -ve error code */
167
pxl_impl_allocate_interp_instance(pl_interp_implementation_t *impl,
168
                                  gs_memory_t * mem)
169
8.09k
{
170
    /* Allocate everything up front */
171
8.09k
    pxl_interp_instance_t *pxli      /****** SHOULD HAVE A STRUCT DESCRIPTOR ******/
172
8.09k
        = (pxl_interp_instance_t *) gs_alloc_bytes(mem,
173
8.09k
                                                   sizeof
174
8.09k
                                                   (pxl_interp_instance_t),
175
8.09k
                                                   "pxl_allocate_interp_instance(pxl_interp_instance_t)");
176
8.09k
    gs_gstate *pgs = gs_gstate_alloc(mem);
177
8.09k
    px_parser_state_t *st = px_process_alloc(mem);      /* parser init, cheap */
178
8.09k
    px_state_t *pxs = px_state_alloc(mem);      /* inits interp state, potentially expensive */
179
180
    /* If allocation error, deallocate & return */
181
8.09k
    if (!pxli || !pgs || !st || !pxs) {
182
0
        if (pxli)
183
0
            gs_free_object(mem, pxli,
184
0
                           "pxl_impl_allocate_interp_instance(pxl_interp_instance_t)");
185
0
        if (pgs)
186
0
            gs_gstate_free(pgs);
187
0
        if (st)
188
0
            px_process_release(st);
189
0
        if (pxs)
190
0
            px_state_release(pxs);
191
0
        return gs_error_VMerror;
192
0
    }
193
8.09k
    gsicc_init_iccmanager(pgs);
194
195
    /* Setup pointers to allocated mem within instance */
196
8.09k
    pxli->memory = mem;
197
8.09k
    pxli->pgs = pgs;
198
8.09k
    pxli->pxs = pxs;
199
8.09k
    pxli->st = st;
200
201
    /* General init of pxl_state */
202
8.09k
    px_state_init(pxs, pgs);    /*pgs only needed to set pxs as pgs' client */
203
8.09k
    pxs->client_data = pxli;
204
8.09k
    pxs->end_page = pxl_end_page_top;   /* after px_state_init */
205
206
8.09k
    pxs->pjls = pl_main_get_pjl_instance(mem);
207
208
    /* The PCL instance is needed for PassThrough mode */
209
8.09k
    pxs->pcls = pl_main_get_pcl_instance(mem);
210
211
    /* Return success */
212
8.09k
    impl->interp_client_data = pxli;
213
8.09k
    return 0;
214
8.09k
}
215
216
static int
217
pxl_set_icc_params(pl_interp_implementation_t * impl, gs_gstate * pgs)
218
4.58k
{
219
4.58k
    pxl_interp_instance_t *pxli  = impl->interp_client_data;
220
4.58k
    return pl_set_icc_params(pxli->memory, pgs);
221
4.58k
}
222
223
/*
224
 * Set a Boolean parameter.
225
 */
226
static int
227
put_param_bool(pxl_interp_instance_t *pxli, gs_param_name pkey, bool value)
228
6.61k
{
229
6.61k
    gs_c_param_list list;
230
6.61k
    int code;
231
232
6.61k
    gs_c_param_list_write(&list, pxli->memory);
233
6.61k
    code = param_write_bool((gs_param_list *) & list, pkey, &value);
234
6.61k
    if (code >= 0) {
235
6.61k
        gs_c_param_list_read(&list);
236
237
6.61k
        code = gs_gstate_putdeviceparams(pxli->pgs,
238
6.61k
                                         gs_currentdevice(pxli->pgs),
239
6.61k
                                         (gs_param_list *) &list);
240
6.61k
    }
241
242
6.61k
    gs_c_param_list_release(&list);
243
6.61k
    return code;
244
6.61k
}
245
246
/* Prepare interp instance for the next "job" */
247
/* ret 0 ok, else -ve error code */
248
static int
249
pxl_impl_init_job(pl_interp_implementation_t * impl,
250
                  gx_device                  * device)
251
4.58k
{
252
4.58k
    int code = 0;
253
4.58k
    pxl_interp_instance_t *pxli = impl->interp_client_data;
254
4.58k
    px_state_t *pxs = pxli->pxs;
255
4.58k
    gs_memory_t *mem = pxli->memory;
256
257
4.58k
    enum { Sbegin, Ssetdevice, Sinitg, Sgsave, Serase, Sdone } stage;
258
259
4.58k
    px_reset_errors(pxli->pxs);
260
4.58k
    px_process_init(pxli->st, true);
261
262
    /* set input status to: expecting stream header */
263
4.58k
    px_stream_header_init(&pxli->headerState, pxli->st, pxli->pxs);
264
4.58k
    pxli->processState = PSHeader;
265
266
4.58k
    stage = Sbegin;
267
268
4.58k
    pxs->interpolate = pl_main_get_interpolate(mem);
269
4.58k
    pxs->nocache = pl_main_get_nocache(mem);
270
4.58k
    pxs->high_level_device = pl_main_get_high_level_device(mem);
271
4.58k
    pxs->supports_rasterops = pl_main_get_rasterop_support(mem);
272
4.58k
    gs_setscanconverter(pxli->pgs, pl_main_get_scanconverter(mem));
273
274
4.58k
    if (pxs->nocache)
275
0
        gs_setcachelimit(pxs->font_dir, 0);
276
277
    /* Set the device into the gstate */
278
4.58k
    stage = Ssetdevice;
279
4.58k
    if ((code = gs_setdevice_no_erase(pxli->pgs, device)) < 0)  /* can't erase yet */
280
0
        goto pisdEnd;
281
282
    /* Warn the device that PXL uses ROPs. */
283
4.58k
    if (code == 0) {
284
2.03k
        code = put_param_bool(pxli, "LanguageUsesROPs", true);
285
286
2.03k
        if (!device->is_open)
287
0
            code = gs_opendevice(device);
288
2.03k
    }
289
290
    /* Init XL graphics */
291
4.58k
    stage = Sinitg;
292
4.58k
    if ((code = px_initgraphics(pxli->pxs)) < 0)
293
0
        goto pisdEnd;
294
295
4.58k
    code = pxl_set_icc_params(impl, pxli->pgs);
296
4.58k
    if (code < 0)
297
0
        goto pisdEnd;
298
299
    /* Do inits of gstate that may be reset by setdevice */
300
4.58k
    gs_setaccuratecurves(pxli->pgs, true);      /* All H-P languages want accurate curves. */
301
302
    /* gsave and grestore (among other places) assume that */
303
    /* there are at least 2 gstates on the graphics stack. */
304
    /* Ensure that now. */
305
4.58k
    stage = Sgsave;
306
4.58k
    if ((code = gs_gsave(pxli->pgs)) < 0)
307
0
        goto pisdEnd;
308
309
4.58k
    stage = Serase;
310
4.58k
    if ((code = gs_erasepage(pxli->pgs)) < 0)
311
0
        goto pisdEnd;
312
313
4.58k
    stage = Sdone;              /* success */
314
    /* Unwind any errors */
315
4.58k
  pisdEnd:
316
4.58k
    switch (stage) {
317
4.58k
        case Sdone:            /* don't undo success */
318
4.58k
            break;
319
320
0
        case Serase:           /* gs_erasepage failed */
321
            /* undo  gsave */
322
0
            gs_grestore_only(pxli->pgs);        /* destroys gs_save stack */
323
            /* fall thru to next */
324
0
        case Sgsave:           /* gsave failed */
325
0
        case Sinitg:
326
            /* undo setdevice */
327
0
            gs_nulldevice(pxli->pgs);
328
            /* fall thru to next */
329
330
0
        case Ssetdevice:       /* gs_setdevice failed */
331
0
        case Sbegin:           /* nothing left to undo */
332
0
            break;
333
4.58k
    }
334
335
4.58k
    return code;
336
4.58k
}
337
338
/* Do any setup for parser per-cursor */
339
static int
340
pxl_impl_process_begin(pl_interp_implementation_t * impl)
341
4.58k
{
342
4.58k
    return 0;
343
4.58k
}
344
345
/* Parse a cursor-full of data */
346
/* ret 0 or +ve if ok, else -ve error code */
347
static int
348
pxl_impl_process(pl_interp_implementation_t * impl,
349
                 stream_cursor_read * cursor)
350
5.15k
{
351
5.15k
    pxl_interp_instance_t *pxli = impl->interp_client_data;
352
5.15k
    int code = 0;
353
354
    /* Process some input */
355
5.15k
    switch (pxli->processState) {
356
0
    case PSDone:
357
0
        return e_ExitLanguage;
358
4.59k
    case PSHeader:         /* Input stream header */
359
4.59k
        code = px_stream_header_process(&pxli->headerState, cursor);
360
4.59k
        if (code == 0)
361
50
            break;          /* need more input later */
362
4.54k
        else if (code < 0) {        /* stream header termination */
363
6
            pxli->processState = PSDone;
364
6
            return code;    /* return error */
365
4.53k
        } else {
366
4.53k
            pxli->processState = PSXL;
367
4.53k
        }
368
        /* fall thru to PSXL */
369
5.09k
    case PSXL:             /* PCL XL */
370
5.09k
        code = px_process(pxli->st, pxli->pxs, cursor);
371
5.09k
        if (code == e_ExitLanguage) {
372
1.94k
            pxli->processState = PSDone;
373
3.14k
        } else if (code == errorWarningsReported) {
374
            /* The parser doesn't skip over the EndSession */
375
            /* operator, because an "error" occurred. */
376
0
            cursor->ptr++;
377
3.14k
        } else if (code < 0)
378
            /* Map library error codes to PCL XL codes when possible. */
379
2.39k
            switch (code) {
380
3
            case gs_error_invalidfont:
381
3
                code = errorIllegalFontData;
382
3
                break;
383
0
            case gs_error_limitcheck:
384
0
                code = errorInternalOverflow;
385
0
                break;
386
2
            case gs_error_nocurrentpoint:
387
2
                code = errorCurrentCursorUndefined;
388
2
                break;
389
2
            case gs_error_rangecheck:
390
2
                code = errorIllegalAttributeValue;
391
2
                break;
392
0
            case gs_error_VMerror:
393
0
                code = errorInsufficientMemory;
394
0
                break;
395
2.39k
            }
396
5.09k
        break;              /* may need more input later */
397
5.15k
    }
398
5.14k
    return code;
399
5.15k
}
400
401
static int
402
pxl_impl_process_end(pl_interp_implementation_t * impl)
403
4.58k
{
404
4.58k
    return 0;
405
4.58k
}
406
407
408
/* Skip to end of job ret 1 if done, 0 ok but EOJ not found, else -ve error code */
409
static int
410
pxl_impl_flush_to_eoj(pl_interp_implementation_t * impl,
411
                      stream_cursor_read * cursor)
412
3.41k
{
413
3.41k
    const byte *p = cursor->ptr;
414
3.41k
    const byte *rlimit = cursor->limit;
415
416
    /* Skip to, but leave UEL in buffer for PJL to find later */
417
2.80M
    for (; p < rlimit; ++p)
418
2.80M
        if (p[1] == '\033') {
419
52.5k
            uint avail = rlimit - p;
420
421
52.5k
            if (memcmp(p + 1, "\033%-12345X", min(avail, 9)))
422
50.9k
                continue;
423
1.60k
            if (avail < 9)
424
24
                break;
425
1.57k
            cursor->ptr = p;
426
1.57k
            return 1;           /* found eoj */
427
1.60k
        }
428
1.84k
    cursor->ptr = p;
429
1.84k
    return 0;                   /* need more */
430
3.41k
}
431
432
/* Parser action for end-of-file */
433
/* ret 0 or +ve if ok, else -ve error code */
434
static int
435
pxl_impl_process_eof(pl_interp_implementation_t * impl)
436
234
{
437
234
    pxl_interp_instance_t *pxli = impl->interp_client_data;
438
439
234
    px_state_cleanup(pxli->pxs);
440
234
    px_process_init(pxli->st, true);
441
442
234
    return 0;
443
234
}
444
445
/* Report any errors after running a job */
446
/* ret 0 ok, else -ve error code */
447
static int
448
pxl_impl_report_errors(pl_interp_implementation_t * impl,
449
                       int code,
450
                       long file_position,
451
                       bool force_to_cout)
452
2.40k
{
453
2.40k
    pxl_interp_instance_t *pxli = impl->interp_client_data;
454
2.40k
    px_parser_state_t *st = pxli->st;
455
2.40k
    px_state_t *pxs = pxli->pxs;
456
2.40k
    int report = pxs->error_report;
457
2.40k
    const char *subsystem = (code <= px_error_next ? "KERNEL" : "GRAPHICS");
458
2.40k
    char message[px_max_error_line + 1];
459
2.40k
    int N = 0;
460
2.40k
    int y = 0;
461
462
2.40k
    if (code >= 0)
463
0
        return code;            /* not really an error */
464
2.40k
    if (report & eErrorPage) {
465
2.40k
        int ecode = px_begin_error_page(pxs, &y);
466
2.40k
        if (ecode < 0) {
467
0
            return ecode;
468
0
        }
469
2.40k
    }
470
14.4k
    while ((N = px_error_message_line(message, N, subsystem,
471
14.4k
                                      code, st, pxs)) >= 0) {
472
12.0k
        if ((report & eBackChannel) || force_to_cout)
473
7.90k
            errprintf(pxli->memory, "%s", message);
474
12.0k
        if (report & eErrorPage)
475
12.0k
            y = px_error_page_show(message, y, pxs);
476
12.0k
    }
477
2.40k
    if (((report & pxeErrorReport_next) && file_position != -1L)
478
0
        || force_to_cout)
479
2.40k
        errprintf(pxli->memory, "file position of error = %ld\n",
480
2.40k
                  file_position);
481
2.40k
    if (report & eErrorPage) {
482
2.40k
        px_args_t args;
483
484
2.40k
        args.pv[0] = 0;
485
2.40k
        pxEndPage(&args, pxs);
486
2.40k
    }
487
2.40k
    px_reset_errors(pxs);
488
489
2.40k
    return code;
490
2.40k
}
491
492
/* Wrap up interp instance after a "job" */
493
/* ret 0 ok, else -ve error code */
494
static int
495
pxl_impl_dnit_job(pl_interp_implementation_t * impl)
496
4.58k
{
497
4.58k
    int code;
498
4.58k
    pxl_interp_instance_t *pxli = impl->interp_client_data;
499
4.58k
    gx_device *device = gs_currentdevice(pxli->pgs);
500
501
4.58k
    px_stream_header_dnit(&pxli->headerState);
502
4.58k
    px_state_cleanup(pxli->pxs);
503
4.58k
    px_process_init(pxli->st, true);
504
    /* return to original gstate  */
505
4.58k
    code = gs_grestore_only(pxli->pgs);        /* destroys gs_save stack */
506
507
    /* Warn the device that ROP usage has come to an end */
508
4.58k
    if (code >= 0) {
509
4.58k
        code = put_param_bool(pxli, "LanguageUsesROPs", false);
510
511
4.58k
        if (!device->is_open)
512
0
            code = gs_opendevice(device);
513
4.58k
    }
514
515
4.58k
    return code;
516
4.58k
}
517
518
/* Deallocate a interpreter instance */
519
/* ret 0 ok, else -ve error code */
520
static int
521
pxl_impl_deallocate_interp_instance(pl_interp_implementation_t * impl)
522
8.09k
{
523
8.09k
    pxl_interp_instance_t *pxli = impl->interp_client_data;
524
8.09k
    gs_memory_t *mem = pxli->memory;
525
526
8.09k
    px_dict_release(&pxli->pxs->font_dict);
527
8.09k
    px_dict_release(&pxli->pxs->builtin_font_dict);
528
    /* do total dnit of interp state */
529
8.09k
    px_state_finit(pxli->pxs);
530
    /* free halftone cache */
531
8.09k
    gs_gstate_free(pxli->pgs);
532
8.09k
    px_process_release(pxli->st);
533
8.09k
    px_state_release(pxli->pxs);
534
8.09k
    gs_free_object(mem, pxli,
535
8.09k
                   "pxl_impl_deallocate_interp_instance(pxl_interp_instance_t)");
536
8.09k
    return 0;
537
8.09k
}
538
539
/*
540
 * End-of-page called back by PXL
541
 */
542
static int
543
pxl_end_page_top(px_state_t * pxls, int num_copies, int flush)
544
2.42k
{
545
2.42k
    return pl_finish_page(pxls->memory->gs_lib_ctx->top_of_system,
546
2.42k
                          pxls->pgs, num_copies, flush);
547
2.42k
}
548
549
/* Parser implementation descriptor */
550
pl_interp_implementation_t pxl_implementation = {
551
    pxl_impl_characteristics,
552
    pxl_impl_allocate_interp_instance,
553
    NULL,                       /* get_device_memory */
554
    NULL,                       /* set_param */
555
    NULL,                       /* add_path */
556
    NULL,                       /* post_args_init */
557
    pxl_impl_init_job,
558
    NULL,                       /* run_prefix_commands */
559
    NULL,                       /* process_file */
560
    pxl_impl_process_begin,
561
    pxl_impl_process,
562
    pxl_impl_process_end,
563
    pxl_impl_flush_to_eoj,
564
    pxl_impl_process_eof,
565
    pxl_impl_report_errors,
566
    pxl_impl_dnit_job,
567
    pxl_impl_deallocate_interp_instance,
568
    NULL,                       /* pxl_impl_reset */
569
    NULL                        /* interp_client_data */
570
};
571
572
/* ---------- Utility Procs ----------- */
573
/* Initialize the parser state, and session parameters in case we get */
574
/* an error before the session is established. */
575
static int
576
px_top_init(px_parser_state_t * st, px_state_t * pxs, bool big_endian)
577
4.58k
{
578
4.58k
    px_args_t args;
579
4.58k
    px_value_t v[3];
580
581
4.58k
    px_process_init(st, big_endian);
582
583
    /* Measure */
584
4.58k
    v[0].type = pxd_scalar | pxd_ubyte;
585
4.58k
    v[0].value.i = eInch;
586
4.58k
    args.pv[0] = &v[0];
587
    /* UnitsPerMeasure */
588
4.58k
    v[1].type = pxd_xy | pxd_uint16;
589
4.58k
    v[1].value.ia[0] = v[1].value.ia[1] = 100;  /* arbitrary */
590
4.58k
    args.pv[1] = &v[1];
591
    /* ErrorReporting */
592
4.58k
    v[2].type = pxd_scalar | pxd_ubyte;
593
4.58k
    v[2].value.i = eErrorPage;
594
4.58k
    args.pv[2] = &v[2];
595
4.58k
    {
596
4.58k
        int code = pxBeginSession(&args, pxs);
597
598
4.58k
        if (code < 0)
599
0
            return code;
600
4.58k
    }
601
4.58k
    return 0;
602
4.58k
}