Coverage Report

Created: 2022-04-16 11:23

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