Coverage Report

Created: 2025-04-22 06:20

/src/libspectre/ghostscript/psi/psapi.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2020 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
17
18
/* Private internal API to Ghostscript interpreter */
19
20
#include "string_.h"
21
#include "ierrors.h"
22
#include "gscdefs.h"
23
#include "gstypes.h"
24
#include "gdebug.h"
25
#include "psapi.h"  /* Public API */
26
#include "iref.h"
27
#include "iminst.h"
28
#include "imain.h"
29
#include "imainarg.h"
30
#include "gsmemory.h"
31
#include "gsmalloc.h"
32
#include "gslibctx.h"
33
#include "gp.h"
34
#include "gsargs.h"
35
#include "ialloc.h"
36
#include "icstate.h"
37
#include "store.h"
38
#include "iname.h"
39
#include "interp.h"
40
#include "gxgstate.h"
41
42
#ifndef GS_THREADSAFE
43
/* Number of threads to allow per process. Unless GS_THREADSAFE is defined
44
 * more than 1 is guaranteed to fail.
45
 */
46
static int gsapi_instance_counter = 0;
47
static const int gsapi_instance_max = 1;
48
#endif
49
50
51
#ifdef METRO
52
static int GSDLLCALL metro_stdin(void *v, char *buf, int len)
53
{
54
        return 0;
55
}
56
57
static int GSDLLCALL metro_stdout(void *v, const char *str, int len)
58
{
59
#ifdef DEBUG
60
        OutputDebugStringWRT(str, len);
61
#endif
62
        return len;
63
}
64
65
static int GSDLLCALL metro_stderr(void *v, const char *str, int len)
66
{
67
        return metro_stdout(v, str, len);
68
}
69
#endif
70
71
/* Create a new instance of Ghostscript.
72
 * First instance per process call with *pinstance == NULL
73
 * next instance in a proces call with *pinstance == copy of valid_instance pointer
74
 * *pinstance is set to a new instance pointer.
75
 */
76
int
77
psapi_new_instance(gs_lib_ctx_t **pinstance,
78
                   void          *caller_handle)
79
218
{
80
218
    gs_memory_t *mem = NULL;
81
218
    gs_main_instance *minst = NULL;
82
83
218
    if (pinstance == NULL)
84
0
        return gs_error_Fatal;
85
86
218
#ifndef GS_THREADSAFE
87
    /* limited to 1 instance, till it works :) */
88
218
    if ( gsapi_instance_counter >= gsapi_instance_max )
89
0
        return gs_error_Fatal;
90
218
    ++gsapi_instance_counter;
91
218
#endif
92
93
218
    mem = gs_malloc_init_with_context(*pinstance);
94
218
    if (mem == NULL)
95
0
        return gs_error_Fatal;
96
218
    minst = gs_main_alloc_instance(mem);
97
218
    if (minst == NULL) {
98
0
        gs_malloc_release(mem);
99
0
        return gs_error_Fatal;
100
0
    }
101
218
    mem->gs_lib_ctx->top_of_system = (void*) minst;
102
218
    mem->gs_lib_ctx->core->default_caller_handle = caller_handle;
103
218
    mem->gs_lib_ctx->core->custom_color_callback = NULL;
104
#ifdef METRO
105
    if (mem->gs_lib_ctx->core->stdin_fn == NULL)
106
        mem->gs_lib_ctx->core->stdin_fn = metro_stdin;
107
    if (mem->gs_lib_ctx->core->stdout_fn == NULL)
108
        mem->gs_lib_ctx->core->stdout_fn = metro_stdout;
109
    if (mem->gs_lib_ctx->core->stderr_fn == NULL)
110
        mem->gs_lib_ctx->core->stderr_fn = metro_stderr;
111
#endif
112
218
    mem->gs_lib_ctx->core->poll_fn = NULL;
113
114
218
    *pinstance = mem->gs_lib_ctx;
115
218
    return psapi_set_arg_encoding(*pinstance, PS_ARG_ENCODING_LOCAL);
116
218
}
117
118
/* Set an instance of Ghostscript to respond to UEL (universal
119
 * exit language) strings in the input. */
120
void
121
psapi_act_on_uel(gs_lib_ctx_t *ctx)
122
0
{
123
0
    ctx->core->act_on_uel = 1;
124
0
}
125
126
/* Destroy an instance of Ghostscript */
127
/* We do not support multiple instances, so make sure
128
 * we use the default instance only once.
129
 */
130
void
131
psapi_delete_instance(gs_lib_ctx_t *ctx)
132
218
{
133
218
    gs_memory_t *mem;
134
218
    gs_main_instance *minst;
135
136
218
    if (ctx == NULL)
137
0
        return;
138
139
218
    mem = (gs_memory_t *)(ctx->memory);
140
218
    minst = get_minst_from_memory(ctx->memory);
141
142
218
    ctx->core->default_caller_handle = NULL;
143
218
    ctx->core->stdin_fn = NULL;
144
218
    ctx->core->stdout_fn = NULL;
145
218
    ctx->core->stderr_fn = NULL;
146
218
    ctx->core->poll_fn = NULL;
147
218
    minst->display = NULL;
148
149
218
    if (minst->param_list) {
150
0
        gs_c_param_list_release(minst->param_list);
151
0
        gs_free_object(minst->heap, minst->param_list, "psapi_delete_instance");
152
0
    }
153
154
218
    gs_c_param_list_release(&minst->enum_params);
155
218
    gs_free_object(minst->heap, minst->enum_keybuf, "psapi_delete_instance");
156
157
218
    gs_free_object(mem, minst, "init_main_instance");
158
159
    /* Release the memory (frees up everything) */
160
218
    gs_malloc_release(mem);
161
162
218
#ifndef GS_THREADSAFE
163
218
    --gsapi_instance_counter;
164
218
#endif
165
218
}
166
167
static int utf16le_get_codepoint(gp_file *file, const char **astr)
168
0
{
169
0
    int c;
170
0
    int rune;
171
0
    int trail;
172
173
    /* This code spots the BOM for 16bit LE and ignores it. Strictly speaking
174
     * this may be wrong, as we are only supposed to ignore it at the beginning
175
     * of the string, but if anyone is stupid enough to use ZWNBSP (zero width
176
     * non breaking space) in the middle of their strings, then they deserve
177
     * what they get. */
178
    /* We spot the BOM for 16bit BE and treat that as EOF. We'd rather give
179
     * up on dealing with a broken file than try to run something we know to
180
     * be wrong. */
181
182
0
    do {
183
0
        if (file) {
184
0
            rune = gp_fgetc(file);
185
0
            if (rune == EOF)
186
0
                return EOF;
187
0
            c = gp_fgetc(file);
188
0
            if (c == EOF)
189
0
                return EOF;
190
0
            rune += c<<8;
191
0
        } else {
192
0
            rune = (*astr)[0] | ((*astr)[1]<<8);
193
0
            if (rune != 0)
194
0
                (*astr) += 2;
195
0
            else
196
0
                return EOF;
197
0
        }
198
0
        if (rune == 0xFEFF) /* BOM - ignore it */
199
0
            continue;
200
0
        if (rune == 0xFFFE) /* BOM for BE - hopelessly broken */
201
0
            return EOF;
202
0
        if (rune < 0xD800 || rune >= 0xE000)
203
0
            return rune;
204
0
        if (rune >= 0xDC00) /* Found a trailing surrogate pair. Skip it */
205
0
            continue;
206
0
lead: /* We've just read a leading surrogate */
207
0
        rune -= 0xD800;
208
0
        rune <<= 10;
209
0
        if (file) {
210
0
            trail = gp_fgetc(file);
211
0
            if (trail == EOF)
212
0
                return EOF;
213
0
            c = gp_fgetc(file);
214
0
            if (c == EOF)
215
0
                return EOF;
216
0
            trail += c<<8;
217
0
        } else {
218
0
            trail = (*astr)[0] | ((*astr)[1]<<8);
219
0
            if (trail != 0)
220
0
                (*astr) += 2;
221
0
            else
222
0
                return EOF;
223
0
        }
224
0
        if (trail < 0xd800 || trail >= 0xE000) {
225
0
            if (rune == 0xFEFF) /* BOM - ignore it. */
226
0
                continue;
227
0
            if (rune == 0xFFFE) /* BOM for BE - hopelessly broken. */
228
0
                return EOF;
229
            /* No trail surrogate was found, so skip the lead surrogate and
230
             * return the rune we landed on. */
231
0
            return trail;
232
0
        }
233
0
        if (trail < 0xdc00) {
234
            /* We found another leading surrogate. */
235
0
            rune = trail;
236
0
            goto lead;
237
0
        }
238
0
        break;
239
0
    } while (1);
240
241
0
    return rune + (trail-0xDC00) + 0x10000;
242
0
}
243
244
/* Initialise the interpreter */
245
int
246
psapi_set_arg_encoding(gs_lib_ctx_t *ctx, int encoding)
247
218
{
248
218
    if (ctx == NULL)
249
0
        return gs_error_Fatal;
250
251
218
    if (encoding == PS_ARG_ENCODING_LOCAL) {
252
#if defined(__WIN32__) && !defined(METRO)
253
        /* For windows, we need to set it up so that we convert from 'local'
254
         * format (in this case whatever codepage is set) to utf8 format. At
255
         * the moment, all the other OS we care about provide utf8 anyway.
256
         */
257
        gs_main_inst_arg_decode(get_minst_from_memory(ctx->memory), gp_local_arg_encoding_get_codepoint);
258
#else
259
218
        gs_main_inst_arg_decode(get_minst_from_memory(ctx->memory), NULL);
260
218
#endif /* WIN32 */
261
218
        return 0;
262
218
    }
263
0
    if (encoding == PS_ARG_ENCODING_UTF8) {
264
0
        gs_main_inst_arg_decode(get_minst_from_memory(ctx->memory), NULL);
265
0
        return 0;
266
0
    }
267
0
    if (encoding == PS_ARG_ENCODING_UTF16LE) {
268
0
        gs_main_inst_arg_decode(get_minst_from_memory(ctx->memory), utf16le_get_codepoint);
269
0
        return 0;
270
0
    }
271
0
    return gs_error_Fatal;
272
0
}
273
274
int
275
psapi_init_with_args(gs_lib_ctx_t *ctx, int argc, char **argv)
276
218
{
277
218
    if (ctx == NULL)
278
0
        return gs_error_Fatal;
279
280
218
    return gs_main_init_with_args(get_minst_from_memory(ctx->memory), argc, argv);
281
218
}
282
283
int
284
psapi_init_with_args01(gs_lib_ctx_t *ctx, int argc, char **argv)
285
0
{
286
0
    if (ctx == NULL)
287
0
        return gs_error_Fatal;
288
289
0
    return gs_main_init_with_args01(get_minst_from_memory(ctx->memory), argc, argv);
290
0
}
291
292
int
293
psapi_init_with_args2(gs_lib_ctx_t *ctx)
294
0
{
295
0
    if (ctx == NULL)
296
0
        return gs_error_Fatal;
297
298
0
    return gs_main_init_with_args2(get_minst_from_memory(ctx->memory));
299
0
}
300
301
int
302
psapi_set_device_param(gs_lib_ctx_t *ctx,
303
                       gs_param_list *plist)
304
0
{
305
0
    gs_main_instance *minst = get_minst_from_memory(ctx->memory);
306
307
0
    return gs_putdeviceparams(minst->i_ctx_p->pgs->device, plist);
308
0
}
309
310
int
311
psapi_get_device_params(gs_lib_ctx_t *ctx,
312
                        gs_param_list *plist)
313
0
{
314
0
    gs_main_instance *minst = get_minst_from_memory(ctx->memory);
315
316
0
    if (minst->i_ctx_p->pgs->device == NULL)
317
0
        return 0;
318
0
    return gs_getdeviceparams(minst->i_ctx_p->pgs->device, plist);
319
0
}
320
321
int
322
psapi_set_param(gs_lib_ctx_t *ctx,
323
                gs_param_list *plist)
324
0
{
325
0
    gs_main_instance *minst = get_minst_from_memory(ctx->memory);
326
327
0
    return gs_main_set_language_param(minst, plist);
328
0
}
329
330
int
331
psapi_add_path(gs_lib_ctx_t *ctx,
332
               const char   *path)
333
0
{
334
0
    gs_main_instance *minst = get_minst_from_memory(ctx->memory);
335
336
0
    return gs_main_add_lib_path(minst, path);
337
0
}
338
339
/* The gsapi_run_* functions are like gs_main_run_* except
340
 * that the error_object is omitted.
341
 * An error object in minst is used instead.
342
 */
343
344
/* Setup up a suspendable run_string */
345
int
346
psapi_run_string_begin(gs_lib_ctx_t *ctx,
347
                       int           user_errors,
348
                       int          *pexit_code)
349
0
{
350
0
    gs_main_instance *minst;
351
0
    int code;
352
353
0
    if (ctx == NULL)
354
0
        return gs_error_Fatal;
355
0
    minst = get_minst_from_memory(ctx->memory);
356
357
0
    if (minst->mid_run_string == 1)
358
0
        return -1;
359
0
    minst->mid_run_string = 1;
360
361
0
    code = gs_main_run_string_begin(minst, user_errors, pexit_code,
362
0
                                    &(minst->error_object));
363
0
    if (code < 0)
364
0
        minst->mid_run_string = 0;
365
366
0
    return code;
367
0
}
368
369
int
370
psapi_run_string_continue(gs_lib_ctx_t *ctx,
371
                          const char   *str,
372
                          unsigned int  length,
373
                          int         user_errors,
374
                          int        *pexit_code)
375
0
{
376
0
    gs_main_instance *minst;
377
0
    int code;
378
379
0
    if (ctx == NULL)
380
0
        return gs_error_Fatal;
381
0
    minst = get_minst_from_memory(ctx->memory);
382
383
0
    code = gs_main_run_string_continue(minst, str, length, user_errors,
384
0
                                       pexit_code,
385
0
                                       &(minst->error_object));
386
0
    if (code < 0)
387
0
        minst->mid_run_string = 0;
388
389
0
    return code;
390
0
}
391
392
uint
393
psapi_get_uel_offset(gs_lib_ctx_t *ctx)
394
0
{
395
0
    if (ctx == NULL)
396
0
        return 0;
397
398
0
    return gs_main_get_uel_offset(get_minst_from_memory(ctx->memory));
399
0
}
400
401
int
402
psapi_run_string_end(gs_lib_ctx_t *ctx,
403
                     int           user_errors,
404
                     int          *pexit_code)
405
0
{
406
0
    int code;
407
0
    gs_main_instance *minst;
408
409
0
    if (ctx == NULL)
410
0
        return gs_error_Fatal;
411
0
    minst = get_minst_from_memory(ctx->memory);
412
413
0
    code = gs_main_run_string_end(minst, user_errors, pexit_code,
414
0
                                  &(minst->error_object));
415
416
0
    minst->mid_run_string = 0;
417
0
    return code;
418
0
}
419
420
int
421
psapi_run_string_with_length(gs_lib_ctx_t *ctx,
422
                             const char   *str,
423
                             unsigned int  length,
424
                             int           user_errors,
425
                             int          *pexit_code)
426
217
{
427
217
    if (ctx == NULL)
428
0
        return gs_error_Fatal;
429
430
217
    return gs_main_run_string_with_length(get_minst_from_memory(ctx->memory),
431
217
                                          str, length, user_errors, pexit_code,
432
217
                                          &(get_minst_from_memory(ctx->memory)->error_object));
433
217
}
434
435
int
436
psapi_run_string(gs_lib_ctx_t *ctx,
437
                 const char   *str,
438
                 int           user_errors,
439
                 int          *pexit_code)
440
0
{
441
0
    if (ctx == NULL)
442
0
        return gs_error_Fatal;
443
444
0
    return gs_main_run_string(get_minst_from_memory(ctx->memory),
445
0
                              str, user_errors, pexit_code,
446
0
                              &(get_minst_from_memory(ctx->memory)->error_object));
447
0
}
448
449
int
450
psapi_run_file(gs_lib_ctx_t *ctx,
451
               const char   *file_name,
452
               int           user_errors,
453
               int          *pexit_code)
454
0
{
455
0
    char *d, *temp;
456
0
    const char *c = file_name;
457
0
    char dummy[6];
458
0
    int rune, code, len;
459
0
    gs_main_instance *minst;
460
0
    if (ctx == NULL)
461
0
        return gs_error_Fatal;
462
0
    minst = get_minst_from_memory(ctx->memory);
463
464
0
    if (minst->mid_run_string == 1)
465
0
        return -1;
466
467
    /* Convert the file_name to utf8 */
468
0
    if (minst->get_codepoint) {
469
0
        len = 1;
470
0
        while ((rune = minst->get_codepoint(NULL, &c)) >= 0)
471
0
            len += codepoint_to_utf8(dummy, rune);
472
0
        temp = (char *)gs_alloc_bytes_immovable(ctx->memory, len, "gsapi_run_file");
473
0
        if (temp == NULL)
474
0
            return 0;
475
0
        c = file_name;
476
0
        d = temp;
477
0
        while ((rune = minst->get_codepoint(NULL, &c)) >= 0)
478
0
           d += codepoint_to_utf8(d, rune);
479
0
        *d = 0;
480
0
    }
481
0
    else {
482
0
      temp = (char *)file_name;
483
0
    }
484
0
    code = gs_main_run_file2(minst, temp, user_errors, pexit_code,
485
0
                             &(minst->error_object));
486
0
    if (temp != file_name)
487
0
        gs_free_object(ctx->memory, temp, "gsapi_run_file");
488
0
    return code;
489
0
}
490
491
/* Retrieve the memory allocator for the interpreter instance */
492
gs_memory_t *
493
psapi_get_device_memory(gs_lib_ctx_t *ctx)
494
0
{
495
0
    if (ctx == NULL)
496
0
        return NULL;
497
0
    return gs_main_get_device_memory(get_minst_from_memory(ctx->memory));
498
0
}
499
500
/* Retrieve the memory allocator for the interpreter instance */
501
int
502
psapi_set_device(gs_lib_ctx_t *ctx, gx_device *pdev)
503
0
{
504
0
    if (ctx == NULL)
505
0
        return gs_error_Fatal;
506
0
    return gs_main_set_device(get_minst_from_memory(ctx->memory), pdev);
507
0
}
508
509
/* Exit the interpreter */
510
int
511
psapi_exit(gs_lib_ctx_t *ctx)
512
218
{
513
218
    if (ctx == NULL)
514
0
        return gs_error_Fatal;
515
516
218
    gs_to_exit(ctx->memory, 0);
517
218
    return 0;
518
218
}
519
520
int
521
psapi_force_geometry(gs_lib_ctx_t *ctx, const float *resolutions, const long *dimensions)
522
0
{
523
0
    int code;
524
525
0
    if (ctx == NULL)
526
0
        return gs_error_Fatal;
527
0
    code = gs_main_force_resolutions(get_minst_from_memory(ctx->memory), resolutions);
528
0
    if (code < 0)
529
0
        return code;
530
0
    return gs_main_force_dimensions(get_minst_from_memory(ctx->memory), dimensions);
531
0
}