Coverage Report

Created: 2026-04-01 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pcl/pl/plapi.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
#include "plapi.h"
17
#include "plmain.h"
18
#include "gsmchunk.h"
19
#include "gsmalloc.h"
20
#include "gserrors.h"
21
#include "gsexit.h"
22
23
#include "gp.h"
24
#include "gscdefs.h"
25
#include "gsmemory.h"
26
#include "stream.h"
27
28
/* Return revision numbers and strings of Ghostscript. */
29
/* Used for determining if wrong GSDLL loaded. */
30
/* This may be called before any other function. */
31
GSDLLEXPORT int GSDLLAPI
32
gsapi_revision(gsapi_revision_t *pr, int rvsize)
33
0
{
34
0
    if (rvsize < sizeof(gsapi_revision_t))
35
0
        return sizeof(gsapi_revision_t);
36
0
    pr->product = gs_product;
37
0
    pr->copyright = gs_copyright;
38
0
    pr->revision = gs_revision;
39
0
    pr->revisiondate = gs_revisiondate;
40
0
    return 0;
41
0
}
42
43
GSDLLEXPORT int GSDLLAPI
44
gsapi_new_instance(void **lib, void *caller_handle)
45
8.09k
{
46
8.09k
    gs_memory_t *heap_mem = gs_malloc_init();
47
8.09k
    gs_memory_t *chunk_mem;
48
8.09k
    pl_main_instance_t *minst;
49
8.09k
    int code;
50
51
8.09k
    if (heap_mem == NULL)
52
0
        return gs_error_Fatal;
53
54
8.09k
    code = gs_memory_chunk_wrap(&chunk_mem, heap_mem);
55
8.09k
    if (code < 0) {
56
0
        gs_malloc_release(heap_mem);
57
0
        return gs_error_Fatal;
58
0
    }
59
60
8.09k
    minst = pl_main_alloc_instance(chunk_mem);
61
8.09k
    if (minst == NULL) {
62
0
        gs_malloc_release(gs_memory_chunk_unwrap(chunk_mem));
63
0
        return gs_error_Fatal;
64
0
    }
65
66
8.09k
    *lib = (void *)(chunk_mem->gs_lib_ctx);
67
8.09k
    chunk_mem->gs_lib_ctx->core->default_caller_handle = caller_handle;
68
69
8.09k
    return 0;
70
8.09k
}
71
72
GSDLLEXPORT int GSDLLAPI
73
gsapi_set_stdio(void *instance,
74
    int (GSDLLCALLPTR stdin_fn)(void *caller_handle, char *buf, int len),
75
    int (GSDLLCALLPTR stdout_fn)(void *caller_handle, const char *str, int len),
76
    int (GSDLLCALLPTR stderr_fn)(void *caller_handle, const char *str, int len))
77
182k
{
78
182k
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
79
80
182k
    if (ctx == NULL)
81
0
        return gs_error_Fatal;
82
182k
    return gsapi_set_stdio_with_handle(instance,
83
182k
                                       stdin_fn, stdout_fn, stderr_fn,
84
182k
                                       ctx->core->default_caller_handle);
85
182k
}
86
87
GSDLLEXPORT int GSDLLAPI
88
gsapi_set_stdio_with_handle(void *instance,
89
    int (GSDLLCALLPTR stdin_fn)(void *caller_handle, char *buf, int len),
90
    int (GSDLLCALLPTR stdout_fn)(void *caller_handle, const char *str, int len),
91
    int (GSDLLCALLPTR stderr_fn)(void *caller_handle, const char *str, int len),
92
    void *caller_handle)
93
182k
{
94
182k
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
95
96
182k
    if (ctx == NULL)
97
0
        return gs_error_Fatal;
98
182k
    ctx->core->stdin_fn  = stdin_fn;
99
182k
    ctx->core->stdout_fn = stdout_fn;
100
182k
    ctx->core->stderr_fn = stderr_fn;
101
182k
    ctx->core->std_caller_handle = caller_handle;
102
103
182k
    return 0;
104
182k
}
105
106
GSDLLEXPORT int GSDLLAPI
107
gsapi_init_with_args(void *lib, int argc, char **argv)
108
182k
{
109
182k
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)lib;
110
182k
    if (lib == NULL)
111
0
        return gs_error_Fatal;
112
113
182k
    gp_set_debug_mem_ptr(ctx->memory);
114
182k
    return pl_main_init_with_args(pl_main_get_instance(ctx->memory), argc, argv);
115
182k
}
116
117
GSDLLEXPORT int GSDLLAPI
118
gsapi_run_file(void *lib, const char *file_name, int user_errors, int *pexit_code)
119
0
{
120
0
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)lib;
121
0
    int code, code1;
122
123
0
    if (pexit_code != NULL)
124
0
        *pexit_code = 0;
125
126
0
    if (lib == NULL)
127
0
        return gs_error_Fatal;
128
129
0
    gp_set_debug_mem_ptr(ctx->memory);
130
0
    code = gs_add_control_path(ctx->memory, gs_permit_file_reading, file_name);
131
0
    if (code < 0) return code;
132
133
0
    code = pl_main_run_file(pl_main_get_instance(ctx->memory), file_name);
134
135
0
    code1 = gs_remove_control_path(ctx->memory, gs_permit_file_reading, file_name);
136
0
    if (code >= 0 && code1 < 0) code = code1;
137
138
0
    return code;
139
0
}
140
141
GSDLLEXPORT int GSDLLAPI
142
gsapi_exit(void *lib)
143
182k
{
144
182k
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)lib;
145
182k
    if (lib == NULL)
146
0
        return gs_error_Fatal;
147
148
182k
    gp_set_debug_mem_ptr(ctx->memory);
149
182k
    return pl_to_exit(ctx->memory);
150
182k
}
151
152
GSDLLEXPORT int GSDLLAPI
153
gsapi_delete_instance(void *lib)
154
8.09k
{
155
8.09k
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)lib;
156
8.09k
    if (lib == NULL)
157
0
        return gs_error_Fatal;
158
159
8.09k
    gp_set_debug_mem_ptr(ctx->memory);
160
8.09k
    return pl_main_delete_instance(pl_main_get_instance(ctx->memory));
161
8.09k
}
162
163
GSDLLEXPORT int GSDLLAPI gsapi_set_poll(void *instance,
164
    int (GSDLLCALLPTR poll_fn)(void *caller_handle))
165
0
{
166
0
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
167
0
    if (instance == NULL)
168
0
        return gs_error_Fatal;
169
0
    gp_set_debug_mem_ptr(ctx->memory);
170
0
    return gsapi_set_poll_with_handle(instance, poll_fn,
171
0
                                      ctx->core->default_caller_handle);
172
0
}
173
174
GSDLLEXPORT int GSDLLAPI gsapi_set_poll_with_handle(void *instance,
175
    int (GSDLLCALLPTR poll_fn)(void *caller_handle),
176
    void *caller_handle)
177
0
{
178
0
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
179
0
    if (instance == NULL)
180
0
        return gs_error_Fatal;
181
0
    ctx->core->poll_fn = poll_fn;
182
0
    ctx->core->poll_caller_handle = caller_handle;
183
0
    return 0;
184
0
}
185
186
GSDLLEXPORT int GSDLLAPI
187
gsapi_set_display_callback(void *lib, display_callback *callback)
188
0
{
189
0
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)lib;
190
0
    if (lib == NULL)
191
0
        return gs_error_Fatal;
192
0
    gp_set_debug_mem_ptr(ctx->memory);
193
0
    pl_main_set_display_callback(pl_main_get_instance(ctx->memory), callback);
194
0
    return 0;
195
0
}
196
197
GSDLLEXPORT int GSDLLAPI
198
gsapi_set_default_device_list(void *instance, const char *list, int listlen)
199
0
{
200
0
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
201
0
    if (instance == NULL)
202
0
        return gs_error_Fatal;
203
0
    gp_set_debug_mem_ptr(ctx->memory);
204
0
    return gs_lib_ctx_set_default_device_list(ctx->memory, list, listlen);
205
0
}
206
207
GSDLLEXPORT int GSDLLAPI
208
gsapi_get_default_device_list(void *instance, char **list, int *listlen)
209
0
{
210
0
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
211
0
    if (instance == NULL)
212
0
        return gs_error_Fatal;
213
0
    gp_set_debug_mem_ptr(ctx->memory);
214
0
    return gs_lib_ctx_get_default_device_list(ctx->memory, list, listlen);
215
0
}
216
217
static int ascii_get_codepoint(stream *s, const char **astr)
218
0
{
219
0
    if (s)
220
0
        return spgetc(s);
221
0
    else {
222
0
        int rune = **astr;
223
0
        (*astr)++;
224
0
        if (rune != 0)
225
0
            return rune;
226
0
    }
227
0
    return EOF;
228
0
}
229
230
static int utf16le_get_codepoint(stream *s, const char **astr)
231
0
{
232
0
    int c;
233
0
    int rune;
234
0
    int trail;
235
236
    /* This code spots the BOM for 16bit LE and ignores it. Strictly speaking
237
     * this may be wrong, as we are only supposed to ignore it at the beginning
238
     * of the string, but if anyone is stupid enough to use ZWNBSP (zero width
239
     * non breaking space) in the middle of their strings, then they deserve
240
     * what they get. */
241
    /* We spot the BOM for 16bit BE and treat that as EOF. We'd rather give
242
     * up on dealing with a broken file than try to run something we know to
243
     * be wrong. */
244
245
0
    do {
246
0
        if (s) {
247
0
            rune = spgetc(s);
248
0
            if (rune == EOF)
249
0
                return EOF;
250
0
            c = spgetc(s);
251
0
            if (c == EOF)
252
0
                return EOF;
253
0
            rune += c<<8;
254
0
        } else {
255
0
            rune = (*astr)[0] | ((*astr)[1]<<8);
256
0
            if (rune != 0)
257
0
                (*astr) += 2;
258
0
            else
259
0
                return EOF;
260
0
        }
261
0
        if (rune == 0xFEFF) /* BOM - ignore it */
262
0
            continue;
263
0
        if (rune == 0xFFFE) /* BOM for BE - hopelessly broken */
264
0
            return EOF;
265
0
        if (rune < 0xD800 || rune >= 0xE000)
266
0
            return rune;
267
0
        if (rune >= 0xDC00) /* Found a trailing surrogate pair. Skip it */
268
0
            continue;
269
0
lead: /* We've just read a leading surrogate */
270
0
        rune -= 0xD800;
271
0
        rune <<= 10;
272
0
        if (s) {
273
0
            trail = spgetc(s);
274
0
            if (trail == EOF)
275
0
                return EOF;
276
0
            c = spgetc(s);
277
0
            if (c == EOF)
278
0
                return EOF;
279
0
            trail += c<<8;
280
0
        } else {
281
0
            trail = (*astr)[0] | ((*astr)[1]<<8);
282
0
            if (trail != 0)
283
0
                (*astr) += 2;
284
0
            else
285
0
                return EOF;
286
0
        }
287
0
        if (trail < 0xd800 || trail >= 0xE000) {
288
0
            if (rune == 0xFEFF) /* BOM - ignore it. */
289
0
                continue;
290
0
            if (rune == 0xFFFE) /* BOM for BE - hopelessly broken. */
291
0
                return EOF;
292
            /* No trail surrogate was found, so skip the lead surrogate and
293
             * return the rune we landed on. */
294
0
            return trail;
295
0
        }
296
0
        if (trail < 0xdc00) {
297
            /* We found another leading surrogate. */
298
0
            rune = trail;
299
0
            goto lead;
300
0
        }
301
0
        break;
302
0
    } while (1);
303
304
0
    return rune + (trail-0xDC00) + 0x10000;
305
0
}
306
307
/* Initialise the interpreter */
308
GSDLLEXPORT int GSDLLAPI
309
gsapi_set_arg_encoding(void *instance, int encoding)
310
8.09k
{
311
8.09k
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
312
8.09k
    if (instance == NULL)
313
0
        return gs_error_Fatal;
314
315
8.09k
    gp_set_debug_mem_ptr(ctx->memory);
316
8.09k
    if (encoding == PL_ARG_ENCODING_LOCAL) {
317
#if defined(__WIN32__) && !defined(METRO)
318
        /* For windows, we need to set it up so that we convert from 'local'
319
         * format (in this case whatever codepage is set) to utf8 format. At
320
         * the moment, all the other OS we care about provide utf8 anyway.
321
         */
322
        pl_main_set_arg_decode(pl_main_get_instance(ctx->memory), gp_local_arg_encoding_get_codepoint);
323
#else
324
0
        pl_main_set_arg_decode(pl_main_get_instance(ctx->memory), ascii_get_codepoint);
325
0
#endif /* WIN32 */
326
0
        return 0;
327
0
    }
328
8.09k
    if (encoding == PL_ARG_ENCODING_UTF8) {
329
8.09k
        pl_main_set_arg_decode(pl_main_get_instance(ctx->memory), NULL);
330
8.09k
        return 0;
331
8.09k
    }
332
0
    if (encoding == PL_ARG_ENCODING_UTF16LE) {
333
0
        pl_main_set_arg_decode(pl_main_get_instance(ctx->memory), utf16le_get_codepoint);
334
0
        return 0;
335
0
    }
336
0
    return gs_error_Fatal;
337
0
}
338
339
GSDLLEXPORT int GSDLLAPI
340
gsapi_run_string_begin(void *lib, int user_errors, int *pexit_code)
341
0
{
342
0
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)lib;
343
344
0
    if (pexit_code != NULL)
345
0
        *pexit_code = 0;
346
347
0
    if (lib == NULL)
348
0
        return gs_error_Fatal;
349
0
    gp_set_debug_mem_ptr(ctx->memory);
350
0
    return pl_main_run_string_begin(pl_main_get_instance(ctx->memory));
351
0
}
352
353
GSDLLEXPORT int GSDLLAPI
354
gsapi_run_string_continue(void *lib, const char *str, unsigned int length,
355
                          int user_errors, int *pexit_code)
356
0
{
357
0
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)lib;
358
359
0
    if (pexit_code != NULL)
360
0
        *pexit_code = 0;
361
362
0
    if (lib == NULL)
363
0
        return gs_error_Fatal;
364
0
    gp_set_debug_mem_ptr(ctx->memory);
365
0
    return pl_main_run_string_continue(pl_main_get_instance(ctx->memory), str, length);
366
0
}
367
368
GSDLLEXPORT int GSDLLAPI
369
gsapi_run_string_end(void *lib, int user_errors, int *pexit_code)
370
0
{
371
0
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)lib;
372
373
0
    if (pexit_code != NULL)
374
0
        *pexit_code = 0;
375
376
0
    if (lib == NULL)
377
0
        return gs_error_Fatal;
378
0
    gp_set_debug_mem_ptr(ctx->memory);
379
0
    return pl_main_run_string_end(pl_main_get_instance(ctx->memory));
380
0
}
381
382
GSDLLEXPORT int GSDLLAPI
383
gsapi_run_string_with_length(void *lib, const char *str, unsigned int length,
384
                             int user_errors, int *pexit_code)
385
0
{
386
0
    int code = gsapi_run_string_begin(lib, user_errors, pexit_code);
387
0
    if (code < 0)
388
0
        return code;
389
0
    code = gsapi_run_string_continue(lib, str, length, user_errors, pexit_code);
390
0
    if (code < 0 && code != gs_error_NeedInput)
391
0
        return code;
392
0
    code = gsapi_run_string_end(lib, user_errors, pexit_code);
393
0
    if (code == gs_error_NeedInput)
394
0
        return_error(gs_error_Fatal);
395
0
    return code;
396
0
}
397
398
GSDLLEXPORT int GSDLLAPI
399
gsapi_run_string(void *lib, const char *str,
400
                 int user_errors, int *pexit_code)
401
0
{
402
0
    return gsapi_run_string_with_length(lib, str, (unsigned int)strlen(str),
403
0
                                        user_errors, pexit_code);
404
0
}
405
406
GSDLLEXPORT int GSDLLAPI
407
gsapi_set_param(void *lib, const char *param, const void *value, gs_set_param_type type)
408
0
{
409
0
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)lib;
410
0
    if (lib == NULL)
411
0
        return gs_error_Fatal;
412
0
    gp_set_debug_mem_ptr(ctx->memory);
413
0
    return pl_main_set_typed_param(pl_main_get_instance(ctx->memory), (pl_set_param_type)type, param, value);
414
0
}
415
416
GSDLLEXPORT int GSDLLAPI
417
gsapi_get_param(void *lib, const char *param, void *value, gs_set_param_type type)
418
0
{
419
0
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)lib;
420
0
    if (lib == NULL)
421
0
        return gs_error_Fatal;
422
0
    gp_set_debug_mem_ptr(ctx->memory);
423
0
    return pl_main_get_typed_param(pl_main_get_instance(ctx->memory), (pl_set_param_type)type, param, value);
424
0
}
425
426
GSDLLEXPORT int GSDLLAPI
427
gsapi_enumerate_params(void *lib, void **iterator, const char **key, gs_set_param_type *type)
428
0
{
429
0
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)lib;
430
0
    if (lib == NULL)
431
0
        return gs_error_Fatal;
432
0
    gp_set_debug_mem_ptr(ctx->memory);
433
0
    return pl_main_enumerate_params(pl_main_get_instance(ctx->memory),
434
0
                                    iterator, key, (pl_set_param_type*)type);
435
0
}
436
437
GSDLLEXPORT int GSDLLAPI
438
gsapi_add_control_path(void *instance, int type, const char *path)
439
0
{
440
0
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
441
0
    if (ctx == NULL)
442
0
        return gs_error_Fatal;
443
0
    gp_set_debug_mem_ptr(ctx->memory);
444
0
    return gs_add_control_path(ctx->memory, type, path);
445
0
}
446
447
GSDLLEXPORT int GSDLLAPI
448
gsapi_remove_control_path(void *instance, int type, const char *path)
449
0
{
450
0
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
451
0
    if (ctx == NULL)
452
0
        return gs_error_Fatal;
453
0
    gp_set_debug_mem_ptr(ctx->memory);
454
0
    return gs_remove_control_path(ctx->memory, type, path);
455
0
}
456
457
GSDLLEXPORT void GSDLLAPI
458
gsapi_purge_control_paths(void *instance, int type)
459
0
{
460
0
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
461
0
    if (ctx == NULL)
462
0
        return;
463
0
    gp_set_debug_mem_ptr(ctx->memory);
464
0
    gs_purge_control_paths(ctx->memory, type);
465
0
}
466
467
GSDLLEXPORT void GSDLLAPI
468
gsapi_activate_path_control(void *instance, int enable)
469
0
{
470
0
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
471
0
    if (ctx == NULL)
472
0
        return;
473
0
    gp_set_debug_mem_ptr(ctx->memory);
474
0
    gs_activate_path_control(ctx->memory, enable);
475
0
}
476
477
GSDLLEXPORT int GSDLLAPI
478
gsapi_is_path_control_active(void *instance)
479
0
{
480
0
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
481
0
    if (ctx == NULL)
482
0
        return 0;
483
0
    gp_set_debug_mem_ptr(ctx->memory);
484
0
    return gs_is_path_control_active(ctx->memory);
485
0
}
486
487
GSDLLEXPORT int GSDLLAPI
488
gsapi_add_fs(void *instance, gsapi_fs_t *fs, void *secret)
489
0
{
490
0
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
491
0
    if (ctx == NULL)
492
0
        return 0;
493
0
    gp_set_debug_mem_ptr(ctx->memory);
494
0
    return gs_add_fs(ctx->memory, (gs_fs_t *)fs, secret);
495
0
}
496
497
GSDLLEXPORT void GSDLLAPI
498
gsapi_remove_fs(void *instance, gsapi_fs_t *fs, void *secret)
499
0
{
500
0
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
501
0
    if (ctx == NULL)
502
0
        return;
503
0
    gp_set_debug_mem_ptr(ctx->memory);
504
0
    gs_remove_fs(ctx->memory, (gs_fs_t *)fs, secret);
505
0
}
506
507
GSDLLEXPORT int GSDLLAPI gsapi_register_callout(
508
   void *instance, gs_callout fn, void *handle)
509
0
{
510
0
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
511
0
    if (instance == NULL)
512
0
        return gs_error_Fatal;
513
0
    gp_set_debug_mem_ptr(ctx->memory);
514
0
    return gs_lib_ctx_register_callout(ctx->memory, fn, handle);
515
0
}
516
517
/* Deregister a handler for gs callouts. */
518
GSDLLEXPORT void GSDLLAPI gsapi_deregister_callout(
519
   void *instance, gs_callout fn, void *handle)
520
0
{
521
0
    gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
522
0
    if (instance == NULL)
523
0
        return;
524
0
    gp_set_debug_mem_ptr(ctx->memory);
525
0
    gs_lib_ctx_deregister_callout(ctx->memory, fn, handle);
526
0
}