Coverage Report

Created: 2025-06-10 06:49

/src/ghostpdl/base/gslibctx.c
Line
Count
Source (jump to first uncovered line)
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
        Some notes on the structure here:
18
19
        At the top level, we have 'instances' of Ghostscript (or GPL).
20
        Here, 'instance' is short for 'instance of the Ghostscript API'.
21
        Each instance is returned by 'gsapi_new_instance'. Every new
22
        instance gets a unique gs_lib_ctx_core_t. Each instance can be
23
        called from any number of threads, but only from one thread at
24
        a time!
25
26
        Each instance of Ghostscript owns one or more interpreters.
27
        Each interpreter gets a unique gs_lib_ctx_t, that shares the
28
        instance's gs_lib_ctx_core_t.
29
30
        Each interpreter (by which we include the graphics library
31
        called by that interpreter) can make multiple gs_memory_t's.
32
        Certainly, every simultaneous (rendering) thread created by by
33
        the interpreter will get a unique gs_memory_t. These
34
        gs_memory_t's share the same gs_lib_ctx_t (and hence the same
35
        gs_lib_ctx_core_t).
36
*/
37
38
39
/* library context functionality for ghostscript
40
 * api callers get a gs_main_instance
41
 */
42
43
/* Capture stdin/out/err before gs.h redefines them. */
44
#include "stdio_.h"
45
#include "string_.h" /* memset */
46
#include "gp.h"
47
#include "gpmisc.h"
48
#include "gsicc_manage.h"
49
#include "gserrors.h"
50
#include "gscdefs.h"            /* for gs_lib_device_list */
51
#include "gsstruct.h"           /* for gs_gc_root_t */
52
#ifdef WITH_CAL
53
#include "cal.h"
54
#endif
55
#include "gsargs.h"
56
#include "globals.h"
57
58
/* Include the extern for the device list. */
59
extern_gs_lib_device_list();
60
61
/* forward declaration */
62
static void gs_purge_permitted_devices(const gs_memory_t *mem);
63
64
static void
65
gs_lib_ctx_get_real_stdio(FILE **in, FILE **out, FILE **err)
66
8.71k
{
67
8.71k
    *in = stdin;
68
8.71k
    *out = stdout;
69
8.71k
    *err = stderr;
70
8.71k
}
71
72
#include "gslibctx.h"
73
#include "gsmemory.h"
74
75
/*  This sets the directory to prepend to the ICC profile names specified for
76
    defaultgray, defaultrgb, defaultcmyk, proofing, linking, named color and device */
77
int
78
gs_lib_ctx_set_icc_directory(const gs_memory_t *mem_gc, const char* pname,
79
                             int dir_namelen)
80
34.0k
{
81
34.0k
    char *result;
82
34.0k
    gs_lib_ctx_t *p_ctx = mem_gc->gs_lib_ctx;
83
34.0k
    gs_memory_t *p_ctx_mem = p_ctx->memory;
84
85
    /* If it is already set and the incoming is the default then don't set
86
       as we are coming from a VMreclaim which is trying to reset the user
87
       parameter */
88
34.0k
    if (p_ctx->profiledir != NULL && strcmp(pname,DEFAULT_DIR_ICC) == 0) {
89
25.3k
        return 0;
90
25.3k
    }
91
8.71k
    if (p_ctx->profiledir != NULL && p_ctx->profiledir_len > 0) {
92
0
        if (strncmp(pname, p_ctx->profiledir, p_ctx->profiledir_len) == 0) {
93
0
            return 0;
94
0
        }
95
0
        gs_free_object(p_ctx_mem, p_ctx->profiledir,
96
0
                       "gs_lib_ctx_set_icc_directory");
97
0
        p_ctx->profiledir = NULL;
98
0
        p_ctx->profiledir_len = 0;
99
0
    }
100
    /* User param string.  Must allocate in non-gc memory */
101
8.71k
    result = (char*) gs_alloc_bytes(p_ctx_mem, dir_namelen+1,
102
8.71k
                                     "gs_lib_ctx_set_icc_directory");
103
8.71k
    if (result == NULL) {
104
0
        return gs_error_VMerror;
105
0
    }
106
8.71k
    strcpy(result, pname);
107
8.71k
    p_ctx->profiledir = result;
108
8.71k
    p_ctx->profiledir_len = dir_namelen;
109
8.71k
    return 0;
110
8.71k
}
111
112
/* Sets/Gets the string containing the list of default devices we should try */
113
int
114
gs_lib_ctx_set_default_device_list(const gs_memory_t *mem, const char* dev_list_str,
115
                        int list_str_len)
116
8.71k
{
117
8.71k
    char *result;
118
8.71k
    gs_lib_ctx_t *p_ctx = mem->gs_lib_ctx;
119
8.71k
    gs_memory_t *ctx_mem = p_ctx->memory;
120
8.71k
    int code = 0;
121
122
8.71k
    result = (char *)gs_alloc_bytes(ctx_mem, list_str_len + 1,
123
8.71k
             "gs_lib_ctx_set_default_device_list");
124
125
8.71k
    if (result) {
126
8.71k
      gs_free_object(ctx_mem, p_ctx->default_device_list,
127
8.71k
                "gs_lib_ctx_set_default_device_list");
128
129
8.71k
      memcpy(result, dev_list_str, list_str_len);
130
8.71k
      result[list_str_len] = '\0';
131
8.71k
      p_ctx->default_device_list = result;
132
8.71k
    }
133
0
    else {
134
0
        code = gs_note_error(gs_error_VMerror);
135
0
    }
136
8.71k
    return code;
137
8.71k
}
138
139
int
140
gs_lib_ctx_get_default_device_list(const gs_memory_t *mem, char** dev_list_str,
141
                        int *list_str_len)
142
0
{
143
    /* In the case the lib ctx hasn't been initialised */
144
0
    if (mem && mem->gs_lib_ctx && mem->gs_lib_ctx->default_device_list) {
145
0
        *dev_list_str = mem->gs_lib_ctx->default_device_list;
146
0
    }
147
0
    else {
148
0
        *dev_list_str = (char *)gs_dev_defaults;
149
0
    }
150
151
0
    *list_str_len = strlen(*dev_list_str);
152
153
0
    return 0;
154
0
}
155
156
static int
157
gs_lib_ctx_alloc_root_structure(gs_memory_t *mem, gs_gc_root_ptr *rp)
158
26.1k
{
159
26.1k
  int code = 0;
160
161
26.1k
  *rp = gs_raw_alloc_struct_immovable(mem, &st_gc_root_t, "gs_lib_ctx_alloc_root_structure");
162
26.1k
  if (*rp == 0)
163
0
    code = gs_note_error(gs_error_VMerror);
164
165
26.1k
  return code;
166
26.1k
}
167
168
static int
169
fs_file_open_file(const gs_memory_t *mem,
170
                        void        *secret,
171
                  const char        *fname,
172
                  const char        *mode,
173
                        gp_file    **file)
174
3.36M
{
175
3.36M
    FILE *f;
176
177
3.36M
    *file = gp_file_FILE_alloc(mem);
178
3.36M
    if (*file == NULL)
179
0
        return 0;
180
3.36M
    f = gp_fopen_impl(mem->non_gc_memory, fname, mode);
181
3.36M
    if (gp_file_FILE_set(*file, f, fclose)) {
182
3.35M
        *file = NULL;
183
3.35M
        return gs_error_VMerror;
184
3.35M
    }
185
8.71k
    return 0;
186
3.36M
}
187
188
static int
189
fs_file_open_scratch(const gs_memory_t *mem, void *secret, const char *prefix, char *rfname, const char *mode, int rm, gp_file **file)
190
3.67k
{
191
3.67k
    *file = gp_file_FILE_alloc(mem);
192
3.67k
    if (*file == NULL)
193
0
        return gs_error_VMerror;
194
3.67k
    if (gp_file_FILE_set(*file,
195
3.67k
                         gp_open_scratch_file_impl(mem,
196
3.67k
                                                   prefix,
197
3.67k
                                                   rfname,
198
3.67k
                                                   mode,
199
3.67k
                                                   rm),
200
3.67k
                                                   NULL)) {
201
0
        *file = NULL;
202
0
        return gs_error_invalidfileaccess;
203
0
    }
204
205
3.67k
    return 0;
206
3.67k
}
207
208
static int
209
fs_file_open_printer(const gs_memory_t *mem, void *secret, const char *fname, int binary_mode, gp_file **file)
210
2.46k
{
211
2.46k
    FILE *f;
212
2.46k
    int (*close)(FILE *) = NULL;
213
214
2.46k
    *file = gp_file_FILE_alloc(mem);
215
2.46k
    if (*file == NULL)
216
0
        return gs_error_VMerror;
217
2.46k
    f = gp_open_printer_impl(mem->non_gc_memory, fname, &binary_mode, &close);
218
2.46k
    if (gp_file_FILE_set(*file, f, close)) {
219
0
        *file = NULL;
220
0
        return gs_error_invalidfileaccess;
221
0
    }
222
    /* The lgtm comment below is required because on some platforms that function
223
     * does nothing. */
224
2.46k
    gp_setmode_binary_impl(f, binary_mode); /* lgtm [cpp/useless-expression] */
225
226
2.46k
    return 0;
227
2.46k
}
228
229
#ifdef WITH_CAL
230
static void *
231
cal_do_malloc(void *opaque, size_t size)
232
{
233
    gs_memory_t *mem = (gs_memory_t *)opaque;
234
    return gs_alloc_bytes(mem, size, "cal_do_malloc");
235
}
236
237
static void *
238
cal_do_realloc(void *opaque, void *ptr, size_t newsize)
239
{
240
    gs_memory_t *mem = (gs_memory_t *)opaque;
241
    return gs_resize_object(mem, ptr, newsize, "cal_do_malloc");
242
}
243
244
static void
245
cal_do_free(void *opaque, void *ptr)
246
{
247
    gs_memory_t *mem = (gs_memory_t *)opaque;
248
    gs_free_object(mem, ptr, "cal_do_malloc");
249
}
250
251
static cal_allocators cal_allocs =
252
{
253
    cal_do_malloc,
254
    cal_do_realloc,
255
    cal_do_free
256
};
257
#endif
258
259
int gs_lib_ctx_init(gs_lib_ctx_t *ctx, gs_memory_t *mem)
260
8.71k
{
261
8.71k
    gs_lib_ctx_t *pio = NULL;
262
8.71k
    gs_globals *globals;
263
264
    /* Check the non gc allocator is being passed in */
265
8.71k
    if (mem == 0 || mem != mem->non_gc_memory)
266
0
        return_error(gs_error_Fatal);
267
268
    /* Get globals here, earlier than it seems we might need it
269
     * because a side effect of this is ensuring that the thread
270
     * local storage for the malloc pointer is set up. */
271
8.71k
    globals = gp_get_globals();
272
273
    /* Now it's safe to set this. */
274
8.71k
    gp_set_debug_mem_ptr(mem);
275
276
8.71k
    if (mem->gs_lib_ctx) /* one time initialization */
277
0
        return 0;
278
279
8.71k
    pio = (gs_lib_ctx_t*)gs_alloc_bytes_immovable(mem,
280
8.71k
                                                  sizeof(gs_lib_ctx_t),
281
8.71k
                                                  "gs_lib_ctx_init");
282
8.71k
    if(pio == NULL)
283
0
        return -1;
284
285
    /* Wholesale blanking is cheaper than retail, and scales better when new
286
     * fields are added. */
287
8.71k
    memset(pio, 0, sizeof(*pio));
288
289
8.71k
    if (ctx != NULL) {
290
0
        pio->core = ctx->core;
291
0
        gx_monitor_enter((gx_monitor_t *)(pio->core->monitor));
292
0
        pio->core->refs++;
293
0
        gx_monitor_leave((gx_monitor_t *)(pio->core->monitor));
294
8.71k
    } else {
295
8.71k
        pio->core = (gs_lib_ctx_core_t *)gs_alloc_bytes_immovable(mem,
296
8.71k
                                                                  sizeof(gs_lib_ctx_core_t),
297
8.71k
                                                                  "gs_lib_ctx_init(core)");
298
8.71k
        if (pio->core == NULL) {
299
0
            gs_free_object(mem, pio, "gs_lib_ctx_init");
300
0
            return -1;
301
0
        }
302
8.71k
        memset(pio->core, 0, sizeof(*pio->core));
303
8.71k
        pio->core->globals = globals;
304
8.71k
        pio->core->fs = (gs_fs_list_t *)gs_alloc_bytes_immovable(mem,
305
8.71k
                                                                 sizeof(gs_fs_list_t),
306
8.71k
                                                                 "gs_lib_ctx_init(gs_fs_list_t)");
307
8.71k
        if (pio->core->fs == NULL) {
308
0
            gs_free_object(mem, pio->core, "gs_lib_ctx_init");
309
0
            gs_free_object(mem, pio, "gs_lib_ctx_init");
310
0
            return -1;
311
0
        }
312
#ifdef WITH_CAL
313
        pio->core->cal_ctx = cal_init(&cal_allocs, mem);
314
        if (pio->core->cal_ctx == NULL) {
315
            gs_free_object(mem, pio->core->fs, "gs_lib_ctx_init");
316
            gs_free_object(mem, pio->core, "gs_lib_ctx_init");
317
            gs_free_object(mem, pio, "gs_lib_ctx_init");
318
            return -1;
319
        }
320
#endif
321
8.71k
        pio->core->fs->fs.open_file = fs_file_open_file;
322
        /* The iodev will fill this in later, if pipes are enabled */
323
8.71k
        pio->core->fs->fs.open_pipe = NULL;
324
8.71k
        pio->core->fs->fs.open_scratch = fs_file_open_scratch;
325
8.71k
        pio->core->fs->fs.open_printer = fs_file_open_printer;
326
8.71k
        pio->core->fs->secret = NULL;
327
8.71k
        pio->core->fs->memory = mem;
328
8.71k
        pio->core->fs->next   = NULL;
329
330
8.71k
        pio->core->monitor = gx_monitor_alloc(mem);
331
8.71k
        if (pio->core->monitor == NULL)
332
0
            goto core_create_failed;
333
8.71k
        pio->core->refs = 1;
334
8.71k
        pio->core->memory = mem;
335
336
        /* Set the non-zero "shared" things */
337
8.71k
        gs_lib_ctx_get_real_stdio(&pio->core->fstdin, &pio->core->fstdout, &pio->core->fstderr );
338
8.71k
        pio->core->stdin_is_interactive = true;
339
        /* id's 1 through 4 are reserved for Device color spaces; see gscspace.h */
340
8.71k
        pio->core->gs_next_id = 5; /* Cloned contexts share the state */
341
        /* Set scanconverter to 1 (default) */
342
8.71k
        pio->core->scanconverter = GS_SCANCONVERTER_DEFAULT;
343
        /* Initialise the underlying CMS. */
344
8.71k
        pio->core->cms_context = gscms_create(mem);
345
8.71k
        if (pio->core->cms_context == NULL) {
346
0
            gx_monitor_free((gx_monitor_t *)(pio->core->monitor));
347
0
core_create_failed:
348
#ifdef WITH_CAL
349
            cal_fin(pio->core->cal_ctx, mem);
350
#endif
351
0
            gs_free_object(mem, pio->core->fs, "gs_lib_ctx_init");
352
0
            gs_free_object(mem, pio->core, "gs_lib_ctx_init");
353
0
            gs_free_object(mem, pio, "gs_lib_ctx_init");
354
0
            return -1;
355
0
        }
356
8.71k
    }
357
358
    /* Now set the non zero/false/NULL things */
359
8.71k
    pio->memory               = mem;
360
361
    /* Need to set this before calling gs_lib_ctx_set_icc_directory. */
362
8.71k
    mem->gs_lib_ctx = pio;
363
    /* Initialize our default ICCProfilesDir */
364
8.71k
    pio->profiledir = NULL;
365
8.71k
    pio->profiledir_len = 0;
366
8.71k
    pio->icc_color_accuracy = MAX_COLOR_ACCURACY;
367
8.71k
    if (gs_lib_ctx_set_icc_directory(mem, DEFAULT_DIR_ICC, strlen(DEFAULT_DIR_ICC)) < 0)
368
0
      goto Failure;
369
370
8.71k
    if (gs_lib_ctx_set_default_device_list(mem, gs_dev_defaults,
371
8.71k
                                           strlen(gs_dev_defaults)) < 0)
372
0
        goto Failure;
373
374
    /* Initialise any lock required for the jpx codec */
375
8.71k
    if (sjpxd_create(mem))
376
0
        goto Failure;
377
378
8.71k
    pio->client_check_file_permission = NULL;
379
8.71k
    gp_get_realtime(pio->real_time_0);
380
381
8.71k
    if (gs_lib_ctx_alloc_root_structure(mem, &pio->name_table_root))
382
0
        goto Failure;
383
384
8.71k
    if (gs_lib_ctx_alloc_root_structure(mem, &pio->io_device_table_root))
385
0
        goto Failure;
386
387
8.71k
    if (gs_lib_ctx_alloc_root_structure(mem, &pio->font_dir_root))
388
0
        goto Failure;
389
8.71k
    if (gs_add_control_path(mem, gs_permit_file_writing, gp_null_file_name) < 0)
390
0
        goto Failure;
391
392
8.71k
    return 0;
393
394
0
Failure:
395
0
    gs_lib_ctx_fin(mem);
396
0
    return -1;
397
8.71k
}
398
399
static void remove_ctx_pointers(gs_memory_t *mem)
400
8.71k
{
401
8.71k
    mem->gs_lib_ctx = NULL;
402
8.71k
    if (mem->stable_memory && mem->stable_memory != mem)
403
0
        remove_ctx_pointers(mem->stable_memory);
404
8.71k
    if (mem->non_gc_memory && mem->non_gc_memory != mem)
405
0
        remove_ctx_pointers(mem->non_gc_memory);
406
8.71k
    if (mem->thread_safe_memory && mem->thread_safe_memory != mem)
407
0
        remove_ctx_pointers(mem->thread_safe_memory);
408
8.71k
}
409
410
void gs_lib_ctx_fin(gs_memory_t *mem)
411
8.71k
{
412
8.71k
    gs_lib_ctx_t *ctx;
413
8.71k
    gs_memory_t *ctx_mem;
414
8.71k
    int refs, i;
415
8.71k
    gs_fs_list_t *fs;
416
8.71k
    gs_callout_list_t *entry;
417
418
8.71k
    if (!mem || !mem->gs_lib_ctx)
419
0
        return;
420
421
8.71k
    ctx = mem->gs_lib_ctx;
422
8.71k
    ctx_mem = ctx->memory;
423
424
8.71k
    sjpxd_destroy(mem);
425
8.71k
    gs_free_object(ctx_mem, ctx->profiledir,
426
8.71k
        "gs_lib_ctx_fin");
427
428
8.71k
    gs_free_object(ctx_mem, ctx->default_device_list,
429
8.71k
                "gs_lib_ctx_fin");
430
431
8.71k
    gs_free_object(ctx_mem, ctx->name_table_root, "gs_lib_ctx_fin");
432
8.71k
    gs_free_object(ctx_mem, ctx->io_device_table_root, "gs_lib_ctx_fin");
433
8.71k
    gs_free_object(ctx_mem, ctx->font_dir_root, "gs_lib_ctx_fin");
434
435
8.71k
    gx_monitor_enter((gx_monitor_t *)(ctx->core->monitor));
436
8.71k
    refs = --ctx->core->refs;
437
8.71k
    gx_monitor_leave((gx_monitor_t *)(ctx->core->monitor));
438
8.71k
    if (refs == 0) {
439
8.71k
        gscms_destroy(ctx->core->cms_context);
440
8.71k
        gx_monitor_free((gx_monitor_t *)(ctx->core->monitor));
441
#ifdef WITH_CAL
442
        cal_fin(ctx->core->cal_ctx, ctx->core->memory);
443
#endif
444
8.71k
        gs_purge_scratch_files(ctx->core->memory);
445
8.71k
        gs_purge_control_paths(ctx->core->memory, gs_permit_file_reading);
446
8.71k
        gs_purge_control_paths(ctx->core->memory, gs_permit_file_writing);
447
8.71k
        gs_purge_control_paths(ctx->core->memory, gs_permit_file_control);
448
449
8.71k
        gs_purge_permitted_devices(ctx->core->memory);
450
451
8.71k
        fs = ctx->core->fs;
452
17.4k
        while (fs) {
453
8.71k
            gs_fs_list_t *next = fs->next;
454
8.71k
            gs_free_object(fs->memory, fs, "gs_lib_ctx_fin");
455
8.71k
            fs = next;
456
8.71k
        }
457
458
8.71k
        entry = ctx->core->callouts;
459
8.71k
        while (entry) {
460
0
            gs_callout_list_t *next = entry->next;
461
0
            gs_free_object(mem->non_gc_memory, entry, "gs_callout_list_t");
462
0
            entry = next;
463
0
        }
464
465
165k
        for (i = 0; i < ctx->core->argc; i++)
466
156k
            gs_free_object(ctx->core->memory, ctx->core->argv[i], "gs_lib_ctx_arg");
467
8.71k
        gs_free_object(ctx->core->memory, ctx->core->argv, "gs_lib_ctx_args");
468
469
8.71k
        gs_free_object(ctx->core->memory, ctx->core, "gs_lib_ctx_fin");
470
8.71k
    }
471
8.71k
    remove_ctx_pointers(ctx_mem);
472
473
8.71k
    gs_free_object(ctx_mem, ctx, "gs_lib_ctx_init");
474
8.71k
}
475
476
gs_lib_ctx_t *gs_lib_ctx_get_interp_instance(const gs_memory_t *mem)
477
42.9M
{
478
42.9M
    if (mem == NULL)
479
0
        return NULL;
480
42.9M
    return mem->gs_lib_ctx;
481
42.9M
}
482
483
void *gs_lib_ctx_get_cms_context( const gs_memory_t *mem )
484
685k
{
485
685k
    if (mem == NULL)
486
0
        return NULL;
487
685k
    return mem->gs_lib_ctx->core->cms_context;
488
685k
}
489
490
int gs_lib_ctx_get_act_on_uel( const gs_memory_t *mem )
491
8.71k
{
492
8.71k
    if (mem == NULL)
493
0
        return 0;
494
8.71k
    return mem->gs_lib_ctx->core->act_on_uel;
495
8.71k
}
496
497
/* Provide a single point for all "C" stdout and stderr.
498
 */
499
500
int outwrite(const gs_memory_t *mem, const char *str, int len)
501
56.2k
{
502
56.2k
    int code;
503
56.2k
    gs_lib_ctx_t *pio = mem->gs_lib_ctx;
504
56.2k
    gs_lib_ctx_core_t *core = pio->core;
505
506
56.2k
    if (len == 0)
507
0
        return 0;
508
56.2k
    if (core->stdout_is_redirected) {
509
56.2k
        if (core->stdout_to_stderr)
510
0
            return errwrite(mem, str, len);
511
56.2k
        code = gp_fwrite(str, 1, len, core->fstdout2);
512
56.2k
        gp_fflush(core->fstdout2);
513
56.2k
    } else if (core->stdout_fn) {
514
0
        return (*core->stdout_fn)(core->std_caller_handle, str, len);
515
0
    } else {
516
0
        code = fwrite(str, 1, len, core->fstdout);
517
0
        fflush(core->fstdout);
518
0
    }
519
56.2k
    return code;
520
56.2k
}
521
522
int errwrite(const gs_memory_t *mem, const char *str, int len)
523
47.5k
{
524
47.5k
    int code;
525
47.5k
    gs_lib_ctx_t *ctx;
526
47.5k
    gs_lib_ctx_core_t *core;
527
47.5k
    if (len == 0)
528
0
        return 0;
529
47.5k
    if (mem == NULL) {
530
#ifdef DEBUG
531
        mem = gp_get_debug_mem_ptr();
532
        if (mem == NULL)
533
#endif
534
0
            return 0;
535
0
    }
536
47.5k
    ctx = mem->gs_lib_ctx;
537
47.5k
    if (ctx == NULL)
538
0
      return 0;
539
47.5k
    core = ctx->core;
540
47.5k
    if (core->stderr_fn)
541
47.5k
        return (*core->stderr_fn)(core->std_caller_handle, str, len);
542
543
0
    code = fwrite(str, 1, len, core->fstderr);
544
0
    fflush(core->fstderr);
545
0
    return code;
546
47.5k
}
547
548
void outflush(const gs_memory_t *mem)
549
0
{
550
0
    gs_lib_ctx_core_t *core = mem->gs_lib_ctx->core;
551
0
    if (core->stdout_is_redirected) {
552
0
        if (core->stdout_to_stderr) {
553
0
            if (!core->stderr_fn)
554
0
                fflush(core->fstderr);
555
0
        }
556
0
        else
557
0
            gp_fflush(core->fstdout2);
558
0
    }
559
0
    else if (!core->stdout_fn)
560
0
        fflush(core->fstdout);
561
0
}
562
563
void errflush(const gs_memory_t *mem)
564
0
{
565
0
    if (!mem->gs_lib_ctx->core->stderr_fn)
566
0
        fflush(mem->gs_lib_ctx->core->fstderr);
567
    /* else nothing to flush */
568
0
}
569
570
int
571
gs_check_file_permission (gs_memory_t *mem, const char *fname, const int len, const char *permission)
572
480k
{
573
480k
    int code = 0;
574
480k
    if (mem->gs_lib_ctx->client_check_file_permission != NULL) {
575
480k
        code = mem->gs_lib_ctx->client_check_file_permission(mem, fname, len, permission);
576
480k
    }
577
480k
    return code;
578
480k
}
579
580
static void
581
rewrite_percent_specifiers(char *s)
582
8.71k
{
583
8.71k
    char *match_start;
584
585
8.71k
    while (*s)
586
8.71k
    {
587
8.71k
        int flags;
588
        /* Find a % */
589
87.1k
        while (*s && *s != '%')
590
78.4k
            s++;
591
8.71k
        if (*s == 0)
592
8.71k
            return;
593
0
        match_start = s;
594
0
        s++;
595
        /* Skip over flags (just one instance of any given flag, in any order) */
596
0
        flags = 0;
597
0
        while (*s) {
598
0
            if (*s == '-' && (flags & 1) == 0)
599
0
                flags |= 1;
600
0
            else if (*s == '+' && (flags & 2) == 0)
601
0
                flags |= 2;
602
0
            else if (*s == ' ' && (flags & 4) == 0)
603
0
                flags |= 4;
604
0
            else if (*s == '0' && (flags & 8) == 0)
605
0
                flags |= 8;
606
0
            else if (*s == '#' && (flags & 16) == 0)
607
0
                flags |= 16;
608
0
            else
609
0
                break;
610
0
            s++;
611
0
        }
612
        /* Skip over width */
613
0
        while (*s >= '0' && *s <= '9')
614
0
            s++;
615
        /* Skip over .precision */
616
0
        if (*s == '.' && s[1] >= '0' && s[1] <= '9') {
617
0
            s++;
618
0
            while (*s >= '0' && *s <= '9')
619
0
                s++;
620
0
        }
621
        /* Skip over 'l' */
622
0
        if (*s == 'l')
623
0
            s++;
624
0
        if (*s == 'd' ||
625
0
            *s == 'i' ||
626
0
            *s == 'u' ||
627
0
            *s == 'o' ||
628
0
            *s == 'x' ||
629
0
            *s == 'X') {
630
            /* Success! */
631
0
            memset(match_start, '*', s - match_start + 1);
632
0
        }
633
        /* If we have escaped percents ("%%") so the percent
634
           will survive a call to sprintf and co, then we need
635
           to drop the extra one here, because the validation
636
           code will see the string *after* it's been sprintf'ed.
637
         */
638
0
        else if (*s == '%') {
639
0
            char *s0 = s;
640
0
            while (*s0) {
641
0
                *s0 = *(s0 + 1);
642
0
                s0++;
643
0
            }
644
0
        }
645
0
    }
646
8.71k
}
647
648
/* For the OutputFile permission we have to deal with formattable strings
649
   i.e. ones that have "%d" or similar in them. For these we want to replace
650
   everything after the %d with a wildcard "*".
651
   Since we do this in two places (the -s and -o cases) split it into a
652
   function.
653
 */
654
#define IS_WHITESPACE(c) ((c == 0x20) || (c == 0x9) || (c == 0xD) || (c == 0xA))
655
int
656
gs_add_outputfile_control_path(gs_memory_t *mem, const char *fname)
657
8.71k
{
658
8.71k
    char f[gp_file_name_sizeof];
659
8.71k
    int code;
660
661
    /* Be sure the string copy will fit */
662
8.71k
    if (strlen(fname) >= gp_file_name_sizeof)
663
0
        return gs_error_rangecheck;
664
8.71k
    strcpy(f, fname);
665
    /* Try to rewrite any %d (or similar) in the string */
666
8.71k
    rewrite_percent_specifiers(f);
667
668
8.71k
    code = gs_add_control_path(mem, gs_permit_file_control, f);
669
8.71k
    if (code < 0)
670
0
        return code;
671
8.71k
    return gs_add_control_path(mem, gs_permit_file_writing, f);
672
8.71k
}
673
674
int
675
gs_remove_outputfile_control_path(gs_memory_t *mem, const char *fname)
676
0
{
677
0
    char f[gp_file_name_sizeof];
678
0
    int code;
679
680
    /* Be sure the string copy will fit */
681
0
    if (strlen(fname) >= gp_file_name_sizeof)
682
0
        return gs_error_rangecheck;
683
0
    strcpy(f, fname);
684
    /* Try to rewrite any %d (or similar) in the string */
685
0
    rewrite_percent_specifiers(f);
686
687
0
    code = gs_remove_control_path(mem, gs_permit_file_control, f);
688
0
    if (code < 0)
689
0
        return code;
690
0
    return gs_remove_control_path(mem, gs_permit_file_writing, f);
691
0
}
692
693
int
694
gs_add_explicit_control_path(gs_memory_t *mem, const char *arg, gs_path_control_t control)
695
0
{
696
0
    char *p2, *p1 = (char *)arg;
697
0
    const char *lim;
698
0
    int code = 0;
699
700
0
    if (arg == NULL)
701
0
        return 0;
702
0
    lim = arg + strlen(arg);
703
0
    while (code >= 0 && p1 < lim && (p2 = strchr(p1, (int)gp_file_name_list_separator)) != NULL) {
704
0
        code = gs_add_control_path_len(mem, control, p1, (int)(p2 - p1));
705
0
        p1 = p2 + 1;
706
0
    }
707
0
    if (p1 < lim)
708
0
        code = gs_add_control_path_len(mem, control, p1, (int)(lim - p1));
709
0
    return code;
710
0
}
711
712
int
713
gs_add_control_path_len(const gs_memory_t *mem, gs_path_control_t type, const char *path, size_t len)
714
1.21M
{
715
1.21M
    return gs_add_control_path_len_flags(mem, type, path, len, 0);
716
1.21M
}
717
718
int
719
gs_add_control_path_len_flags(const gs_memory_t *mem, gs_path_control_t type, const char *path, size_t len, int flags)
720
1.24M
{
721
1.24M
    gs_path_control_set_t *control;
722
1.24M
    unsigned int n, i;
723
1.24M
    gs_lib_ctx_core_t *core;
724
1.24M
    char *buffer;
725
1.24M
    uint rlen;
726
727
1.24M
    if (path == NULL || len == 0)
728
0
        return 0;
729
730
1.24M
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
731
1.24M
        (core = mem->gs_lib_ctx->core) == NULL)
732
0
        return gs_error_unknownerror;
733
734
1.24M
    switch(type) {
735
1.18M
        case gs_permit_file_reading:
736
1.18M
            control = &core->permit_reading;
737
1.18M
            break;
738
38.5k
        case gs_permit_file_writing:
739
38.5k
            control = &core->permit_writing;
740
38.5k
            break;
741
29.8k
        case gs_permit_file_control:
742
29.8k
            control = &core->permit_control;
743
29.8k
            break;
744
0
        default:
745
0
            return gs_error_rangecheck;
746
1.24M
    }
747
748
    /* "%pipe%" do not follow the normal rules for path definitions, so we
749
       don't "reduce" them to avoid unexpected results
750
     */
751
1.24M
    if (path[0] == '|' || (len > 5 && memcmp(path, "%pipe", 5) == 0)) {
752
0
        buffer = (char *)gs_alloc_bytes(core->memory, len + 1, "gs_add_control_path_len");
753
0
        if (buffer == NULL)
754
0
            return gs_error_VMerror;
755
0
        memcpy(buffer, path, len);
756
0
        buffer[len] = 0;
757
0
        rlen = len;
758
0
    }
759
1.24M
    else {
760
1.24M
        rlen = len + 1;
761
762
1.24M
        buffer = (char *)gs_alloc_bytes(core->memory, rlen, "gs_add_control_path_len");
763
1.24M
        if (buffer == NULL)
764
0
            return gs_error_VMerror;
765
766
1.24M
        if (gp_file_name_reduce(path, (uint)len, buffer, &rlen) != gp_combine_success)
767
0
            return gs_error_invalidfileaccess;
768
1.24M
        buffer[rlen] = 0;
769
1.24M
    }
770
771
1.24M
    n = control->num;
772
10.9M
    for (i = 0; i < n; i++)
773
10.5M
    {
774
10.5M
        if (strncmp(control->entry[i].path, buffer, rlen) == 0 &&
775
10.5M
            control->entry[i].path[rlen] == 0) {
776
914k
            gs_free_object(core->memory, buffer, "gs_add_control_path_len");
777
914k
            return 0; /* Already there! */
778
914k
        }
779
10.5M
    }
780
781
333k
    if (control->num == control->max) {
782
52.3k
        gs_path_control_entry_t *p;
783
784
52.3k
        n = control->max * 2;
785
52.3k
        if (n == 0) {
786
26.1k
            n = 4;
787
26.1k
            p = (gs_path_control_entry_t *)gs_alloc_bytes(core->memory, sizeof(*p)*n, "gs_lib_ctx(entries)");
788
26.1k
        } else
789
26.1k
            p = (gs_path_control_entry_t *)gs_resize_object(core->memory, control->entry, sizeof(*p)*n, "gs_lib_ctx(entries)");
790
52.3k
        if (p == NULL) {
791
0
            gs_free_object(core->memory, buffer, "gs_add_control_path_len");
792
0
            return gs_error_VMerror;
793
0
        }
794
52.3k
        control->entry = p;
795
52.3k
        control->max = n;
796
52.3k
    }
797
798
333k
    n = control->num;
799
333k
    control->entry[n].path = buffer;
800
333k
    control->entry[n].path[len] = 0;
801
333k
    control->entry[n].flags = flags;
802
333k
    control->num++;
803
804
333k
    return 0;
805
333k
}
806
807
int
808
gs_add_control_path(const gs_memory_t *mem, gs_path_control_t type, const char *path)
809
26.1k
{
810
26.1k
    return gs_add_control_path_len_flags(mem, type, path, path ? strlen(path) : 0, 0);
811
26.1k
}
812
813
int
814
gs_add_control_path_flags(const gs_memory_t *mem, gs_path_control_t type, const char *path, int flags)
815
11.0k
{
816
11.0k
    return gs_add_control_path_len_flags(mem, type, path, path ? strlen(path) : 0, flags);
817
11.0k
}
818
819
int
820
gs_remove_control_path_len(const gs_memory_t *mem, gs_path_control_t type, const char *path, size_t len)
821
0
{
822
0
    return gs_remove_control_path_len_flags(mem, type, path, len, 0);
823
0
}
824
825
int
826
gs_remove_control_path_len_flags(const gs_memory_t *mem, gs_path_control_t type, const char *path, size_t len, int flags)
827
0
{
828
0
    gs_path_control_set_t *control;
829
0
    unsigned int n, i;
830
0
    gs_lib_ctx_core_t *core;
831
0
    char *buffer;
832
0
    uint rlen;
833
834
0
    if (path == NULL || len == 0)
835
0
        return 0;
836
837
0
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
838
0
        (core = mem->gs_lib_ctx->core) == NULL)
839
0
        return gs_error_unknownerror;
840
841
0
    switch(type) {
842
0
        case gs_permit_file_reading:
843
0
            control = &core->permit_reading;
844
0
            break;
845
0
        case gs_permit_file_writing:
846
0
            control = &core->permit_writing;
847
0
            break;
848
0
        case gs_permit_file_control:
849
0
            control = &core->permit_control;
850
0
            break;
851
0
        default:
852
0
            return gs_error_rangecheck;
853
0
    }
854
855
    /* "%pipe%" do not follow the normal rules for path definitions, so we
856
       don't "reduce" them to avoid unexpected results
857
     */
858
0
    if (path[0] == '|' || (len > 5 && memcmp(path, "%pipe", 5) == 0)) {
859
0
        buffer = (char *)gs_alloc_bytes(core->memory, len + 1, "gs_remove_control_path_len");
860
0
        if (buffer == NULL)
861
0
            return gs_error_VMerror;
862
0
        memcpy(buffer, path, len);
863
0
        buffer[len] = 0;
864
0
        rlen = len;
865
0
    }
866
0
    else {
867
0
        rlen = len+1;
868
869
0
        buffer = (char *)gs_alloc_bytes(core->memory, rlen, "gs_remove_control_path_len");
870
0
        if (buffer == NULL)
871
0
            return gs_error_VMerror;
872
873
0
        if (gp_file_name_reduce(path, (uint)len, buffer, &rlen) != gp_combine_success)
874
0
            return gs_error_invalidfileaccess;
875
0
        buffer[rlen] = 0;
876
0
    }
877
878
0
    n = control->num;
879
0
    for (i = 0; i < n; i++) {
880
0
        if (control->entry[i].flags == flags &&
881
0
            strncmp(control->entry[i].path, buffer, len) == 0 &&
882
0
            control->entry[i].path[len] == 0)
883
0
            break;
884
0
    }
885
0
    gs_free_object(core->memory, buffer, "gs_remove_control_path_len");
886
0
    if (i == n)
887
0
        return 0;
888
889
0
    gs_free_object(core->memory, control->entry[i].path, "gs_lib_ctx(path)");
890
0
    for (;i < n-1; i++)
891
0
        control->entry[i] = control->entry[i+1];
892
0
    control->num = n-1;
893
894
0
    return 0;
895
0
}
896
897
int
898
gs_remove_control_path(const gs_memory_t *mem, gs_path_control_t type, const char *path)
899
0
{
900
0
    if (path == NULL)
901
0
        return 0;
902
903
0
    return gs_remove_control_path_len_flags(mem, type, path, strlen(path), 0);
904
0
}
905
906
int
907
gs_remove_control_path_flags(const gs_memory_t *mem, gs_path_control_t type, const char *path, int flags)
908
0
{
909
0
    if (path == NULL)
910
0
        return 0;
911
912
0
    return gs_remove_control_path_len_flags(mem, type, path, strlen(path), flags);
913
0
}
914
915
void
916
gs_purge_control_paths(const gs_memory_t *mem, gs_path_control_t type)
917
26.1k
{
918
26.1k
    gs_path_control_set_t *control;
919
26.1k
    unsigned int n, in, out;
920
26.1k
    gs_lib_ctx_core_t *core;
921
922
26.1k
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
923
26.1k
        (core = mem->gs_lib_ctx->core) == NULL)
924
0
        return;
925
926
26.1k
    switch(type) {
927
8.71k
        case gs_permit_file_reading:
928
8.71k
            control = &core->permit_reading;
929
8.71k
            break;
930
8.71k
        case gs_permit_file_writing:
931
8.71k
            control = &core->permit_writing;
932
8.71k
            break;
933
8.71k
        case gs_permit_file_control:
934
8.71k
            control = &core->permit_control;
935
8.71k
            break;
936
0
        default:
937
0
            return;
938
26.1k
    }
939
940
26.1k
    n = control->num;
941
348k
    for (in = out = 0; in < n; in++) {
942
322k
        if (control->entry[in].flags & gs_path_control_flag_is_scratch_file) {
943
            /* Don't purge scratch files! */
944
0
            control->entry[out++] = control->entry[in];
945
0
        } else
946
322k
            gs_free_object(core->memory, control->entry[in].path, "gs_lib_ctx(path)");
947
322k
    }
948
26.1k
    control->num = out;
949
26.1k
    if (out == 0) {
950
26.1k
        gs_free_object(core->memory, control->entry, "gs_lib_ctx(paths)");
951
26.1k
        control->entry = NULL;
952
26.1k
        control->max = 0;
953
26.1k
    }
954
26.1k
}
955
956
void
957
gs_purge_scratch_files(const gs_memory_t *mem)
958
8.71k
{
959
8.71k
    gs_path_control_set_t *control;
960
8.71k
    gs_path_control_t type;
961
8.71k
    int n, in, out;
962
8.71k
    gs_lib_ctx_core_t *core;
963
964
8.71k
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
965
8.71k
        (core = mem->gs_lib_ctx->core) == NULL)
966
0
        return;
967
968
34.8k
    for (type = gs_permit_file_reading; type <= gs_permit_file_control; type++)
969
26.1k
    {
970
26.1k
        switch(type) {
971
0
            default:
972
8.71k
            case gs_permit_file_reading:
973
8.71k
                control = &core->permit_reading;
974
8.71k
                break;
975
8.71k
            case gs_permit_file_writing:
976
8.71k
                control = &core->permit_writing;
977
8.71k
                break;
978
8.71k
            case gs_permit_file_control:
979
8.71k
                control = &core->permit_control;
980
8.71k
                break;
981
26.1k
        }
982
983
26.1k
        n = control->num;
984
359k
        for (in = out = 0; in < n; in++) {
985
333k
            if ((control->entry[in].flags & gs_path_control_flag_is_scratch_file) == 0) {
986
                /* Only purge scratch files! */
987
322k
                control->entry[out++] = control->entry[in];
988
322k
            } else {
989
11.0k
                if (type == gs_permit_file_reading) {
990
                    /* Call gp_unlink_impl, as we don't want gp_unlink
991
                     * to go looking in the lists we are currently
992
                     * manipulating! */
993
3.67k
                    gp_unlink_impl(core->memory, control->entry[in].path);
994
3.67k
                }
995
11.0k
                gs_free_object(core->memory, control->entry[in].path, "gs_lib_ctx(path)");
996
11.0k
            }
997
333k
        }
998
26.1k
        control->num = out;
999
26.1k
        if (out == 0) {
1000
0
            gs_free_object(core->memory, control->entry, "gs_lib_ctx(paths)");
1001
0
            control->entry = NULL;
1002
0
            control->max = 0;
1003
0
        }
1004
26.1k
    }
1005
8.71k
}
1006
1007
void
1008
gs_activate_path_control(gs_memory_t *mem, int enable)
1009
8.71k
{
1010
8.71k
    gs_lib_ctx_core_t *core;
1011
1012
8.71k
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
1013
8.71k
        (core = mem->gs_lib_ctx->core) == NULL)
1014
0
        return;
1015
1016
8.71k
    core->path_control_active = enable;
1017
8.71k
}
1018
1019
int
1020
gs_is_path_control_active(const gs_memory_t *mem)
1021
218k
{
1022
218k
    gs_lib_ctx_core_t *core;
1023
1024
218k
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
1025
218k
        (core = mem->gs_lib_ctx->core) == NULL)
1026
0
        return 0;
1027
1028
218k
    return core->path_control_active;
1029
218k
}
1030
1031
int
1032
gs_add_fs(const gs_memory_t *mem,
1033
                gs_fs_t     *fs,
1034
                void        *secret)
1035
0
{
1036
0
    gs_fs_list_t *fsl;
1037
0
    gs_lib_ctx_core_t *core;
1038
1039
0
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
1040
0
        (core = mem->gs_lib_ctx->core) == NULL)
1041
0
        return gs_error_unknownerror;
1042
1043
0
    fsl = (gs_fs_list_t *)gs_alloc_bytes_immovable(mem->non_gc_memory,
1044
0
                                                   sizeof(gs_fs_list_t),
1045
0
                                                   "gs_fs_list_t");
1046
0
    if (fsl == NULL)
1047
0
        return gs_error_VMerror;
1048
0
    fsl->fs      = *fs;
1049
0
    fsl->secret  = secret;
1050
0
    fsl->memory  = mem->non_gc_memory;
1051
0
    fsl->next    = core->fs;
1052
0
    core->fs     = fsl;
1053
1054
0
    return 0;
1055
0
}
1056
1057
void
1058
gs_remove_fs(const gs_memory_t *mem,
1059
                   gs_fs_t     *rfs,
1060
                   void        *secret)
1061
0
{
1062
0
    gs_fs_list_t **pfs;
1063
0
    gs_lib_ctx_core_t *core;
1064
1065
0
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
1066
0
        (core = mem->gs_lib_ctx->core) == NULL)
1067
0
        return;
1068
1069
0
    pfs = &core->fs;
1070
0
    while (*pfs)
1071
0
    {
1072
0
        gs_fs_list_t *fs = *pfs;
1073
0
        if (fs->fs.open_file == rfs->open_file &&
1074
0
            fs->fs.open_pipe == rfs->open_pipe &&
1075
0
            fs->fs.open_scratch == rfs->open_scratch &&
1076
0
            fs->fs.open_printer == rfs->open_printer &&
1077
0
            fs->secret == secret) {
1078
0
            *pfs = fs->next;
1079
0
            gs_free_object(fs->memory, fs, "gs_fs_t");
1080
0
        } else
1081
0
            pfs = &(*pfs)->next;
1082
0
    }
1083
0
}
1084
1085
static int gs_add_device_control(gs_memory_t *mem, char *device, int len)
1086
0
{
1087
0
    gs_lib_ctx_core_t *core;
1088
0
    char *buffer;
1089
0
    uint rlen, n, i;
1090
1091
0
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
1092
0
        (core = mem->gs_lib_ctx->core) == NULL)
1093
0
        return gs_error_unknownerror;
1094
1095
0
    rlen = len + 1;
1096
1097
0
    buffer = (char *)gs_alloc_bytes(core->memory, rlen, "gs_add_device");
1098
0
    if (buffer == NULL)
1099
0
        return gs_error_VMerror;
1100
1101
0
    memcpy(buffer, device, len);
1102
0
    buffer[len] = 0;
1103
1104
0
    n = core->permitted_devices.num;
1105
0
    for (i = 0; i < n; i++)
1106
0
    {
1107
0
        if (strlen(core->permitted_devices.devices[i]) == len && strncmp(core->permitted_devices.devices[i], buffer, len) == 0) {
1108
0
            gs_free_object(core->memory, buffer, "gs_add_device");
1109
0
            return 0; /* Already there! */
1110
0
        }
1111
0
    }
1112
1113
0
    if (core->permitted_devices.num == core->permitted_devices.max) {
1114
0
        char **table;
1115
1116
0
        n = core->permitted_devices.max * 2;
1117
0
        if (n == 0) {
1118
0
            n = 2;
1119
0
            table = (char **)gs_alloc_bytes(core->memory, sizeof(char *) * n, "gs_add_device_control");
1120
0
            if (table == NULL) {
1121
0
                gs_free_object(core->memory, buffer, "gs_add_device");
1122
0
                return_error(gs_error_VMerror);
1123
0
            }
1124
0
            memset(table, 0x00, sizeof(char *) * n);
1125
0
        } else {
1126
0
            table = (char **)gs_resize_object(core->memory, core->permitted_devices.devices,sizeof(char *) * n, "gs_add_device_control");
1127
0
            if (table == NULL) {
1128
0
                gs_free_object(core->memory, buffer, "gs_add_device");
1129
0
                return_error(gs_error_VMerror);
1130
0
            }
1131
0
            memset(table + core->permitted_devices.max, 0x00, core->permitted_devices.max * sizeof(char *));
1132
0
        }
1133
0
        core->permitted_devices.devices = table;
1134
0
        core->permitted_devices.max = n;
1135
0
    }
1136
0
    n = core->permitted_devices.num;
1137
0
    core->permitted_devices.devices[n] = buffer;
1138
0
    core->permitted_devices.num++;
1139
1140
0
    return 0;
1141
0
}
1142
1143
int
1144
gs_check_device_permission (gs_memory_t *mem, const char *dname, const int len)
1145
0
{
1146
0
    if (mem->gs_lib_ctx->core->permitted_devices.num != 0) {
1147
0
        int i;
1148
0
        char *permit_name = NULL;
1149
1150
0
        for (i=0;i < mem->gs_lib_ctx->core->permitted_devices.num; i++) {
1151
0
            permit_name = mem->gs_lib_ctx->core->permitted_devices.devices[i];
1152
1153
            /* Allow * as a wildcard */
1154
0
            if (permit_name != NULL && strlen(permit_name) == 1 && permit_name[0] == '*')
1155
0
                break;
1156
1157
0
            if (permit_name != NULL && strlen(permit_name) == len &&
1158
0
                strncmp(permit_name, dname, len) == 0)
1159
0
                break;
1160
0
        }
1161
0
        if (i >= mem->gs_lib_ctx->core->permitted_devices.num)
1162
0
            return 0;
1163
0
        return 1;
1164
0
    }
1165
0
    return 0;
1166
0
}
1167
1168
int
1169
gs_add_explicit_permitted_device(gs_memory_t *mem, const char *arg)
1170
0
{
1171
0
    char *p2, *p1 = (char *)arg;
1172
0
    const char *lim;
1173
0
    int code = 0;
1174
1175
0
    if (arg == NULL)
1176
0
        return 0;
1177
0
    lim = arg + strlen(arg);
1178
0
    while (code >= 0 && p1 < lim && (p2 = strchr(p1, gp_file_name_list_separator)) != NULL) {
1179
0
        code = gs_add_device_control(mem, p1, (int)(p2 - p1));
1180
0
        p1 = p2 + 1;
1181
0
    }
1182
0
    if (p1 < lim)
1183
0
        code = gs_add_device_control(mem, p1, (int)(lim - p1));
1184
0
    return code;
1185
0
}
1186
1187
static void
1188
gs_purge_permitted_devices(const gs_memory_t *mem)
1189
8.71k
{
1190
8.71k
    gs_lib_ctx_core_t *core = mem->gs_lib_ctx->core;
1191
8.71k
    uint i;
1192
1193
8.71k
    if (core == NULL)
1194
0
        return;
1195
1196
8.71k
    for (i=0;i < core->permitted_devices.max;i++) {
1197
0
        if (core->permitted_devices.devices[i] != NULL)
1198
0
            gs_free_object(core->memory, core->permitted_devices.devices[i], "gs_purge_permitted_devices");
1199
0
    }
1200
8.71k
    if (core->permitted_devices.devices != NULL)
1201
0
        gs_free_object(core->memory, core->permitted_devices.devices, "gs_purge_permitted_devices");
1202
1203
8.71k
    core->permitted_devices.max = core->permitted_devices.num = 0;
1204
8.71k
    core->permitted_devices.devices = NULL;
1205
8.71k
}
1206
1207
int
1208
gs_lib_ctx_stash_sanitized_arg(gs_lib_ctx_t *ctx, const char *arg)
1209
148k
{
1210
148k
    gs_lib_ctx_core_t *core;
1211
148k
    size_t len;
1212
148k
    const char *p;
1213
148k
    int elide = 0;
1214
1215
148k
    if (ctx == NULL || ctx->core == NULL || arg == NULL)
1216
0
        return 0;
1217
1218
    /* Sanitize arg */
1219
148k
    switch(*arg)
1220
148k
    {
1221
148k
    case '-':
1222
148k
        switch (arg[1])
1223
148k
        {
1224
0
        case 0:   /* We can let - through unchanged */
1225
0
        case '-': /* Need to check for permitted file lists */
1226
            /* By default, we want to keep the key, but lose the value */
1227
0
            p = arg+2;
1228
0
            while (*p && *p != '=' && *p != '#')
1229
0
                p++;
1230
0
            if (*p == '=' || *p == '#')
1231
0
                p++;
1232
0
            if (*p == 0)
1233
0
                break; /* No value to elide */
1234
            /* Check for our blocked values here */
1235
0
#define ARG_MATCHES(STR, ARG, LEN) \
1236
0
    (strlen(STR) == LEN && !memcmp(STR, ARG, LEN))
1237
0
            if (ARG_MATCHES("permit-file-read", arg+2, p-arg-3))
1238
0
                elide=1;
1239
0
            if (ARG_MATCHES("permit-file-write", arg+2, p-arg-3))
1240
0
                elide=1;
1241
0
            if (ARG_MATCHES("permit-file-control", arg+2, p-arg-3))
1242
0
                elide=1;
1243
0
            if (ARG_MATCHES("permit-file-all", arg+2, p-arg-3))
1244
0
                elide=1;
1245
0
#undef ARG_MATCHES
1246
            /* Didn't match a blocked value, so allow it. */
1247
0
            break;
1248
87.1k
        case 'd': /* We can let -dFoo=<whatever> through unchanged */
1249
87.1k
        case 'D': /* We can let -DFoo=<whatever> through unchanged */
1250
95.8k
        case 'r': /* We can let -r through unchanged */
1251
95.8k
        case 'Z': /* We can let -Z through unchanged */
1252
95.8k
        case 'g': /* We can let -g through unchanged */
1253
95.8k
        case 'P': /* We can let -P through unchanged */
1254
95.8k
        case '+': /* We can let -+ through unchanged */
1255
104k
        case '_': /* We can let -_ through unchanged */
1256
104k
        case 'u': /* We can let -u through unchanged */
1257
104k
        case 'q': /* We can let -q through unchanged */
1258
104k
            break;
1259
0
        case 'I': /* Let through the I, but hide anything else */
1260
0
        case 'f': /* Let through the I, but hide anything else */
1261
0
            if (arg[2] == 0)
1262
0
                break;
1263
0
            p = arg+2;
1264
0
            while (*p == 32)
1265
0
                p++;
1266
0
            elide = 1;
1267
0
            break;
1268
34.8k
        case 's':
1269
34.8k
        case 'S':
1270
            /* By default, we want to keep the key, but lose the value */
1271
34.8k
            p = arg+2;
1272
357k
            while (*p && *p != '=' && *p != '#')
1273
322k
                p++;
1274
34.8k
            if (*p == '=' || *p == '#')
1275
34.8k
                p++;
1276
34.8k
            if (*p == 0)
1277
0
                break; /* No value to elide */
1278
            /* Check for our whitelisted values here */
1279
34.8k
#define ARG_MATCHES(STR, ARG, LEN) \
1280
226k
    (strlen(STR) == LEN && !memcmp(STR, ARG, LEN))
1281
34.8k
            if (ARG_MATCHES("DEFAULTPAPERSIZE", arg+2, p-arg-3))
1282
0
                break;
1283
34.8k
            if (ARG_MATCHES("DEVICE", arg+2, p-arg-3))
1284
8.71k
                break;
1285
26.1k
            if (ARG_MATCHES("PAPERSIZE", arg+2, p-arg-3))
1286
0
                break;
1287
26.1k
            if (ARG_MATCHES("SUBSTFONT", arg+2, p-arg-3))
1288
0
                break;
1289
26.1k
            if (ARG_MATCHES("ColorConversionStrategy", arg+2, p-arg-3))
1290
0
                break;
1291
26.1k
            if (ARG_MATCHES("NupControl", arg+2, p-arg-3))
1292
0
                break;
1293
26.1k
            if (ARG_MATCHES("PageList", arg+2, p-arg-3))
1294
0
                break;
1295
26.1k
            if (ARG_MATCHES("ProcessColorModel", arg+2, p-arg-3))
1296
0
                break;
1297
26.1k
#undef ARG_MATCHES
1298
            /* Didn't match a whitelisted value, so elide it. */
1299
26.1k
            elide = 1;
1300
26.1k
            break;
1301
8.71k
        default:
1302
            /* Shouldn't happen, but elide it just in case */
1303
8.71k
            arg = "?";
1304
8.71k
            break;
1305
148k
        }
1306
148k
        break;
1307
148k
    case '@':
1308
        /* Shouldn't happen */
1309
0
    default:
1310
        /* Anything else should be elided */
1311
0
        arg = "?";
1312
0
        break;
1313
148k
    }
1314
1315
148k
    core = ctx->core;
1316
148k
    if (elide)
1317
26.1k
        len = p-arg;
1318
122k
    else
1319
122k
        len = strlen(arg);
1320
1321
148k
    if (core->arg_max == core->argc) {
1322
26.1k
        char **argv;
1323
26.1k
        int newlen = core->arg_max * 2;
1324
26.1k
        if (newlen == 0)
1325
0
            newlen = 4;
1326
26.1k
        argv = (char **)gs_alloc_bytes(ctx->core->memory, sizeof(char *) * newlen,
1327
26.1k
                                       "gs_lib_ctx_args");
1328
26.1k
        if (argv == NULL)
1329
0
            return gs_error_VMerror;
1330
26.1k
        if (core->argc > 0) {
1331
26.1k
            memcpy(argv, core->argv, sizeof(char *) * core->argc);
1332
26.1k
            gs_free_object(ctx->memory, core->argv, "gs_lib_ctx_args");
1333
26.1k
        }
1334
26.1k
        core->argv = argv;
1335
26.1k
        core->arg_max = newlen;
1336
26.1k
    }
1337
1338
148k
    core->argv[core->argc] = (char *)gs_alloc_bytes(ctx->core->memory, len+1+elide,
1339
148k
                                                    "gs_lib_ctx_arg");
1340
148k
    if (core->argv[core->argc] == NULL)
1341
0
        return gs_error_VMerror;
1342
148k
    memcpy(core->argv[core->argc], arg, len);
1343
148k
    if (elide) {
1344
26.1k
        core->argv[core->argc][len] = '?';
1345
26.1k
    }
1346
148k
    core->argv[core->argc][len+elide] = 0;
1347
148k
    core->argc++;
1348
1349
148k
    return 0;
1350
148k
}
1351
1352
int
1353
gs_lib_ctx_stash_exe(gs_lib_ctx_t *ctx, const char *arg)
1354
8.71k
{
1355
8.71k
    gs_lib_ctx_core_t *core;
1356
8.71k
    size_t len;
1357
8.71k
    const char *p, *word;
1358
8.71k
    const char *sep = gp_file_name_directory_separator();
1359
8.71k
    size_t seplen = strlen(sep);
1360
1361
8.71k
    if (ctx == NULL || ctx->core == NULL || arg == NULL)
1362
0
        return 0;
1363
1364
    /* Sanitize arg */
1365
8.71k
    p = arg;
1366
8.71k
    word = NULL;
1367
26.1k
    for (p = arg; *p; p++) {
1368
17.4k
        if (memcmp(sep, p, seplen) == 0) {
1369
0
            word = p+seplen;
1370
0
            p += seplen-1;
1371
0
        }
1372
#if defined(__WIN32__) || defined(__OS2__) || defined(METRO)
1373
        if (*p == '\\')
1374
            word = p+1;
1375
#endif
1376
17.4k
    }
1377
8.71k
    len = p - (word ? word : arg) + 1;
1378
8.71k
    if (word)
1379
0
        len += 5;
1380
1381
8.71k
    core = ctx->core;
1382
8.71k
    if (core->arg_max == core->argc) {
1383
8.71k
        char **argv;
1384
8.71k
        int newlen = core->arg_max * 2;
1385
8.71k
        if (newlen == 0)
1386
8.71k
            newlen = 4;
1387
8.71k
        argv = (char **)gs_alloc_bytes(ctx->core->memory, sizeof(char *) * newlen,
1388
8.71k
                                       "gs_lib_ctx_args");
1389
8.71k
        if (argv == NULL)
1390
0
            return gs_error_VMerror;
1391
8.71k
        if (core->argc > 0) {
1392
0
            memcpy(argv, core->argv, sizeof(char *) * core->argc);
1393
0
            gs_free_object(ctx->memory, core->argv, "gs_lib_ctx_args");
1394
0
        }
1395
8.71k
        core->argv = argv;
1396
8.71k
        core->arg_max = newlen;
1397
8.71k
    }
1398
1399
8.71k
    core->argv[core->argc] = (char *)gs_alloc_bytes(ctx->core->memory, len,
1400
8.71k
                                                    "gs_lib_ctx_arg");
1401
8.71k
    if (core->argv[core->argc] == NULL)
1402
0
        return gs_error_VMerror;
1403
8.71k
    if (word)
1404
0
        strcpy(core->argv[core->argc], "path/");
1405
8.71k
    else
1406
8.71k
        core->argv[core->argc][0] = 0;
1407
8.71k
    strcat(core->argv[core->argc], word ? word : arg);
1408
8.71k
    core->argc++;
1409
1410
8.71k
    return 0;
1411
8.71k
}
1412
1413
int gs_lib_ctx_get_args(gs_lib_ctx_t *ctx, const char * const **argv)
1414
0
{
1415
0
    gs_lib_ctx_core_t *core;
1416
1417
0
    if (ctx == NULL || ctx->core == NULL || argv == NULL)
1418
0
        return 0;
1419
1420
0
    core = ctx->core;
1421
0
    *argv = (const char * const *)core->argv;
1422
0
    return core->argc;
1423
0
}
1424
1425
int gs_lib_ctx_register_callout(gs_memory_t *mem, gs_callout_fn fn, void *arg)
1426
0
{
1427
0
    gs_lib_ctx_core_t *core;
1428
0
    gs_callout_list_t *entry;
1429
1430
0
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
1431
0
        mem->gs_lib_ctx->core == NULL || fn == NULL)
1432
0
        return 0;
1433
1434
0
   core = mem->gs_lib_ctx->core;
1435
0
   entry = (gs_callout_list_t *)gs_alloc_bytes(core->memory,
1436
0
                                               sizeof(*entry),
1437
0
                                               "gs_callout_list_t");
1438
0
   if (entry == NULL)
1439
0
       return_error(gs_error_VMerror);
1440
0
   entry->next = core->callouts;
1441
0
   entry->callout = fn;
1442
0
   entry->handle = arg;
1443
0
   core->callouts = entry;
1444
1445
0
   return 0;
1446
0
}
1447
1448
void gs_lib_ctx_deregister_callout(gs_memory_t *mem, gs_callout_fn fn, void *arg)
1449
0
{
1450
0
    gs_lib_ctx_core_t *core;
1451
0
    gs_callout_list_t **entry;
1452
1453
0
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
1454
0
        mem->gs_lib_ctx->core == NULL || fn == NULL)
1455
0
        return;
1456
1457
0
   core = mem->gs_lib_ctx->core;
1458
0
   entry = &core->callouts;
1459
0
   while (*entry) {
1460
0
        if ((*entry)->callout == fn && (*entry)->handle == arg) {
1461
0
            gs_callout_list_t *next = (*entry)->next;
1462
0
            gs_free_object(core->memory, *entry, "gs_callout_list_t");
1463
0
            *entry = next;
1464
0
        } else {
1465
0
            entry = &(*entry)->next;
1466
0
        }
1467
0
   }
1468
0
}
1469
1470
int gs_lib_ctx_callout(gs_memory_t *mem, const char *dev_name,
1471
                       int id, int size, void *data)
1472
0
{
1473
0
    gs_lib_ctx_core_t *core;
1474
0
    gs_callout_list_t *entry;
1475
1476
0
    if (mem == NULL || mem->gs_lib_ctx == NULL || mem->gs_lib_ctx->core == NULL)
1477
0
        return -1;
1478
1479
0
    core = mem->gs_lib_ctx->core;
1480
0
    entry = core->callouts;
1481
0
    while (entry) {
1482
0
        int code = entry->callout(mem->gs_lib_ctx->top_of_system,
1483
0
                                  entry->handle, dev_name, id, size, data);
1484
0
        if (code >= 0)
1485
0
            return code;
1486
0
        if (code != gs_error_unknownerror)
1487
0
            return code;
1488
0
        entry = entry->next;
1489
0
    }
1490
0
    return -1;
1491
0
}
1492
1493
int gs_lib_ctx_nts_adjust(gs_memory_t *mem, int adjust)
1494
0
{
1495
0
    gs_lib_ctx_core_t *core;
1496
0
    int ret = 0;
1497
0
    gs_globals *globals;
1498
1499
0
    if (adjust == 0)
1500
0
        return 0;
1501
1502
0
    if (mem == NULL || mem->gs_lib_ctx == NULL || mem->gs_lib_ctx->core == NULL)
1503
0
        return_error(gs_error_unknownerror);
1504
1505
0
    core = mem->gs_lib_ctx->core;
1506
0
    globals = core->globals;
1507
0
    if (globals == NULL)
1508
0
        return 0; /* No globals means just once instance. Adjustment is pointless. */
1509
1510
0
    gp_global_lock(globals);
1511
0
    if (adjust > 0 && globals->non_threadsafe_count != 0)
1512
0
        ret = gs_error_unknownerror; /* We already have one non threadsafe device running. */
1513
0
    else if (adjust < 0 && globals->non_threadsafe_count == 0)
1514
0
        ret = gs_error_unknownerror; /* This indicates something has gone very wrong! */
1515
0
    else
1516
0
        globals->non_threadsafe_count += adjust;
1517
0
    gp_global_unlock(globals);
1518
1519
0
    if (ret)
1520
0
        ret = gs_note_error(ret);
1521
0
    return ret;
1522
0
}
1523
1524
void gs_globals_init(gs_globals *globals)
1525
1
{
1526
1
    memset(globals, 0, sizeof(*globals));
1527
1
}