Coverage Report

Created: 2025-06-10 06:59

/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
9.86k
{
67
9.86k
    *in = stdin;
68
9.86k
    *out = stdout;
69
9.86k
    *err = stderr;
70
9.86k
}
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
45.9k
{
81
45.9k
    char *result;
82
45.9k
    gs_lib_ctx_t *p_ctx = mem_gc->gs_lib_ctx;
83
45.9k
    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
45.9k
    if (p_ctx->profiledir != NULL && strcmp(pname,DEFAULT_DIR_ICC) == 0) {
89
36.0k
        return 0;
90
36.0k
    }
91
9.86k
    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
9.86k
    result = (char*) gs_alloc_bytes(p_ctx_mem, dir_namelen+1,
102
9.86k
                                     "gs_lib_ctx_set_icc_directory");
103
9.86k
    if (result == NULL) {
104
0
        return gs_error_VMerror;
105
0
    }
106
9.86k
    strcpy(result, pname);
107
9.86k
    p_ctx->profiledir = result;
108
9.86k
    p_ctx->profiledir_len = dir_namelen;
109
9.86k
    return 0;
110
9.86k
}
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
9.86k
{
117
9.86k
    char *result;
118
9.86k
    gs_lib_ctx_t *p_ctx = mem->gs_lib_ctx;
119
9.86k
    gs_memory_t *ctx_mem = p_ctx->memory;
120
9.86k
    int code = 0;
121
122
9.86k
    result = (char *)gs_alloc_bytes(ctx_mem, list_str_len + 1,
123
9.86k
             "gs_lib_ctx_set_default_device_list");
124
125
9.86k
    if (result) {
126
9.86k
      gs_free_object(ctx_mem, p_ctx->default_device_list,
127
9.86k
                "gs_lib_ctx_set_default_device_list");
128
129
9.86k
      memcpy(result, dev_list_str, list_str_len);
130
9.86k
      result[list_str_len] = '\0';
131
9.86k
      p_ctx->default_device_list = result;
132
9.86k
    }
133
0
    else {
134
0
        code = gs_note_error(gs_error_VMerror);
135
0
    }
136
9.86k
    return code;
137
9.86k
}
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
29.5k
{
159
29.5k
  int code = 0;
160
161
29.5k
  *rp = gs_raw_alloc_struct_immovable(mem, &st_gc_root_t, "gs_lib_ctx_alloc_root_structure");
162
29.5k
  if (*rp == 0)
163
0
    code = gs_note_error(gs_error_VMerror);
164
165
29.5k
  return code;
166
29.5k
}
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
5.31M
{
175
5.31M
    FILE *f;
176
177
5.31M
    *file = gp_file_FILE_alloc(mem);
178
5.31M
    if (*file == NULL)
179
0
        return 0;
180
5.31M
    f = gp_fopen_impl(mem->non_gc_memory, fname, mode);
181
5.31M
    if (gp_file_FILE_set(*file, f, fclose)) {
182
5.30M
        *file = NULL;
183
5.30M
        return gs_error_VMerror;
184
5.30M
    }
185
9.86k
    return 0;
186
5.31M
}
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
5.15k
{
191
5.15k
    *file = gp_file_FILE_alloc(mem);
192
5.15k
    if (*file == NULL)
193
0
        return gs_error_VMerror;
194
5.15k
    if (gp_file_FILE_set(*file,
195
5.15k
                         gp_open_scratch_file_impl(mem,
196
5.15k
                                                   prefix,
197
5.15k
                                                   rfname,
198
5.15k
                                                   mode,
199
5.15k
                                                   rm),
200
5.15k
                                                   NULL)) {
201
0
        *file = NULL;
202
0
        return gs_error_invalidfileaccess;
203
0
    }
204
205
5.15k
    return 0;
206
5.15k
}
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
4.23k
{
211
4.23k
    FILE *f;
212
4.23k
    int (*close)(FILE *) = NULL;
213
214
4.23k
    *file = gp_file_FILE_alloc(mem);
215
4.23k
    if (*file == NULL)
216
0
        return gs_error_VMerror;
217
4.23k
    f = gp_open_printer_impl(mem->non_gc_memory, fname, &binary_mode, &close);
218
4.23k
    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
4.23k
    gp_setmode_binary_impl(f, binary_mode); /* lgtm [cpp/useless-expression] */
225
226
4.23k
    return 0;
227
4.23k
}
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
9.86k
{
261
9.86k
    gs_lib_ctx_t *pio = NULL;
262
9.86k
    gs_globals *globals;
263
264
    /* Check the non gc allocator is being passed in */
265
9.86k
    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
9.86k
    globals = gp_get_globals();
272
273
    /* Now it's safe to set this. */
274
9.86k
    gp_set_debug_mem_ptr(mem);
275
276
9.86k
    if (mem->gs_lib_ctx) /* one time initialization */
277
0
        return 0;
278
279
9.86k
    pio = (gs_lib_ctx_t*)gs_alloc_bytes_immovable(mem,
280
9.86k
                                                  sizeof(gs_lib_ctx_t),
281
9.86k
                                                  "gs_lib_ctx_init");
282
9.86k
    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
9.86k
    memset(pio, 0, sizeof(*pio));
288
289
9.86k
    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
9.86k
    } else {
295
9.86k
        pio->core = (gs_lib_ctx_core_t *)gs_alloc_bytes_immovable(mem,
296
9.86k
                                                                  sizeof(gs_lib_ctx_core_t),
297
9.86k
                                                                  "gs_lib_ctx_init(core)");
298
9.86k
        if (pio->core == NULL) {
299
0
            gs_free_object(mem, pio, "gs_lib_ctx_init");
300
0
            return -1;
301
0
        }
302
9.86k
        memset(pio->core, 0, sizeof(*pio->core));
303
9.86k
        pio->core->globals = globals;
304
9.86k
        pio->core->fs = (gs_fs_list_t *)gs_alloc_bytes_immovable(mem,
305
9.86k
                                                                 sizeof(gs_fs_list_t),
306
9.86k
                                                                 "gs_lib_ctx_init(gs_fs_list_t)");
307
9.86k
        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
9.86k
        pio->core->fs->fs.open_file = fs_file_open_file;
322
        /* The iodev will fill this in later, if pipes are enabled */
323
9.86k
        pio->core->fs->fs.open_pipe = NULL;
324
9.86k
        pio->core->fs->fs.open_scratch = fs_file_open_scratch;
325
9.86k
        pio->core->fs->fs.open_printer = fs_file_open_printer;
326
9.86k
        pio->core->fs->secret = NULL;
327
9.86k
        pio->core->fs->memory = mem;
328
9.86k
        pio->core->fs->next   = NULL;
329
330
9.86k
        pio->core->monitor = gx_monitor_alloc(mem);
331
9.86k
        if (pio->core->monitor == NULL)
332
0
            goto core_create_failed;
333
9.86k
        pio->core->refs = 1;
334
9.86k
        pio->core->memory = mem;
335
336
        /* Set the non-zero "shared" things */
337
9.86k
        gs_lib_ctx_get_real_stdio(&pio->core->fstdin, &pio->core->fstdout, &pio->core->fstderr );
338
9.86k
        pio->core->stdin_is_interactive = true;
339
        /* id's 1 through 4 are reserved for Device color spaces; see gscspace.h */
340
9.86k
        pio->core->gs_next_id = 5; /* Cloned contexts share the state */
341
        /* Set scanconverter to 1 (default) */
342
9.86k
        pio->core->scanconverter = GS_SCANCONVERTER_DEFAULT;
343
        /* Initialise the underlying CMS. */
344
9.86k
        pio->core->cms_context = gscms_create(mem);
345
9.86k
        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
9.86k
    }
357
358
    /* Now set the non zero/false/NULL things */
359
9.86k
    pio->memory               = mem;
360
361
    /* Need to set this before calling gs_lib_ctx_set_icc_directory. */
362
9.86k
    mem->gs_lib_ctx = pio;
363
    /* Initialize our default ICCProfilesDir */
364
9.86k
    pio->profiledir = NULL;
365
9.86k
    pio->profiledir_len = 0;
366
9.86k
    pio->icc_color_accuracy = MAX_COLOR_ACCURACY;
367
9.86k
    if (gs_lib_ctx_set_icc_directory(mem, DEFAULT_DIR_ICC, strlen(DEFAULT_DIR_ICC)) < 0)
368
0
      goto Failure;
369
370
9.86k
    if (gs_lib_ctx_set_default_device_list(mem, gs_dev_defaults,
371
9.86k
                                           strlen(gs_dev_defaults)) < 0)
372
0
        goto Failure;
373
374
    /* Initialise any lock required for the jpx codec */
375
9.86k
    if (sjpxd_create(mem))
376
0
        goto Failure;
377
378
9.86k
    pio->client_check_file_permission = NULL;
379
9.86k
    gp_get_realtime(pio->real_time_0);
380
381
9.86k
    if (gs_lib_ctx_alloc_root_structure(mem, &pio->name_table_root))
382
0
        goto Failure;
383
384
9.86k
    if (gs_lib_ctx_alloc_root_structure(mem, &pio->io_device_table_root))
385
0
        goto Failure;
386
387
9.86k
    if (gs_lib_ctx_alloc_root_structure(mem, &pio->font_dir_root))
388
0
        goto Failure;
389
9.86k
    if (gs_add_control_path(mem, gs_permit_file_writing, gp_null_file_name) < 0)
390
0
        goto Failure;
391
392
9.86k
    return 0;
393
394
0
Failure:
395
0
    gs_lib_ctx_fin(mem);
396
0
    return -1;
397
9.86k
}
398
399
static void remove_ctx_pointers(gs_memory_t *mem)
400
9.86k
{
401
9.86k
    mem->gs_lib_ctx = NULL;
402
9.86k
    if (mem->stable_memory && mem->stable_memory != mem)
403
0
        remove_ctx_pointers(mem->stable_memory);
404
9.86k
    if (mem->non_gc_memory && mem->non_gc_memory != mem)
405
0
        remove_ctx_pointers(mem->non_gc_memory);
406
9.86k
    if (mem->thread_safe_memory && mem->thread_safe_memory != mem)
407
0
        remove_ctx_pointers(mem->thread_safe_memory);
408
9.86k
}
409
410
void gs_lib_ctx_fin(gs_memory_t *mem)
411
9.86k
{
412
9.86k
    gs_lib_ctx_t *ctx;
413
9.86k
    gs_memory_t *ctx_mem;
414
9.86k
    int refs, i;
415
9.86k
    gs_fs_list_t *fs;
416
9.86k
    gs_callout_list_t *entry;
417
418
9.86k
    if (!mem || !mem->gs_lib_ctx)
419
0
        return;
420
421
9.86k
    ctx = mem->gs_lib_ctx;
422
9.86k
    ctx_mem = ctx->memory;
423
424
9.86k
    sjpxd_destroy(mem);
425
9.86k
    gs_free_object(ctx_mem, ctx->profiledir,
426
9.86k
        "gs_lib_ctx_fin");
427
428
9.86k
    gs_free_object(ctx_mem, ctx->default_device_list,
429
9.86k
                "gs_lib_ctx_fin");
430
431
9.86k
    gs_free_object(ctx_mem, ctx->name_table_root, "gs_lib_ctx_fin");
432
9.86k
    gs_free_object(ctx_mem, ctx->io_device_table_root, "gs_lib_ctx_fin");
433
9.86k
    gs_free_object(ctx_mem, ctx->font_dir_root, "gs_lib_ctx_fin");
434
435
9.86k
    gx_monitor_enter((gx_monitor_t *)(ctx->core->monitor));
436
9.86k
    refs = --ctx->core->refs;
437
9.86k
    gx_monitor_leave((gx_monitor_t *)(ctx->core->monitor));
438
9.86k
    if (refs == 0) {
439
9.86k
        gscms_destroy(ctx->core->cms_context);
440
9.86k
        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
9.86k
        gs_purge_scratch_files(ctx->core->memory);
445
9.86k
        gs_purge_control_paths(ctx->core->memory, gs_permit_file_reading);
446
9.86k
        gs_purge_control_paths(ctx->core->memory, gs_permit_file_writing);
447
9.86k
        gs_purge_control_paths(ctx->core->memory, gs_permit_file_control);
448
449
9.86k
        gs_purge_permitted_devices(ctx->core->memory);
450
451
9.86k
        fs = ctx->core->fs;
452
19.7k
        while (fs) {
453
9.86k
            gs_fs_list_t *next = fs->next;
454
9.86k
            gs_free_object(fs->memory, fs, "gs_lib_ctx_fin");
455
9.86k
            fs = next;
456
9.86k
        }
457
458
9.86k
        entry = ctx->core->callouts;
459
9.86k
        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
187k
        for (i = 0; i < ctx->core->argc; i++)
466
177k
            gs_free_object(ctx->core->memory, ctx->core->argv[i], "gs_lib_ctx_arg");
467
9.86k
        gs_free_object(ctx->core->memory, ctx->core->argv, "gs_lib_ctx_args");
468
469
9.86k
        gs_free_object(ctx->core->memory, ctx->core, "gs_lib_ctx_fin");
470
9.86k
    }
471
9.86k
    remove_ctx_pointers(ctx_mem);
472
473
9.86k
    gs_free_object(ctx_mem, ctx, "gs_lib_ctx_init");
474
9.86k
}
475
476
gs_lib_ctx_t *gs_lib_ctx_get_interp_instance(const gs_memory_t *mem)
477
57.1M
{
478
57.1M
    if (mem == NULL)
479
0
        return NULL;
480
57.1M
    return mem->gs_lib_ctx;
481
57.1M
}
482
483
void *gs_lib_ctx_get_cms_context( const gs_memory_t *mem )
484
26.7M
{
485
26.7M
    if (mem == NULL)
486
0
        return NULL;
487
26.7M
    return mem->gs_lib_ctx->core->cms_context;
488
26.7M
}
489
490
int gs_lib_ctx_get_act_on_uel( const gs_memory_t *mem )
491
9.86k
{
492
9.86k
    if (mem == NULL)
493
0
        return 0;
494
9.86k
    return mem->gs_lib_ctx->core->act_on_uel;
495
9.86k
}
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
773k
{
502
773k
    int code;
503
773k
    gs_lib_ctx_t *pio = mem->gs_lib_ctx;
504
773k
    gs_lib_ctx_core_t *core = pio->core;
505
506
773k
    if (len == 0)
507
0
        return 0;
508
773k
    if (core->stdout_is_redirected) {
509
773k
        if (core->stdout_to_stderr)
510
0
            return errwrite(mem, str, len);
511
773k
        code = gp_fwrite(str, 1, len, core->fstdout2);
512
773k
        gp_fflush(core->fstdout2);
513
773k
    } 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
773k
    return code;
520
773k
}
521
522
int errwrite(const gs_memory_t *mem, const char *str, int len)
523
20.2k
{
524
20.2k
    int code;
525
20.2k
    gs_lib_ctx_t *ctx;
526
20.2k
    gs_lib_ctx_core_t *core;
527
20.2k
    if (len == 0)
528
0
        return 0;
529
20.2k
    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
20.2k
    ctx = mem->gs_lib_ctx;
537
20.2k
    if (ctx == NULL)
538
0
      return 0;
539
20.2k
    core = ctx->core;
540
20.2k
    if (core->stderr_fn)
541
20.2k
        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
20.2k
}
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
1.06M
{
573
1.06M
    int code = 0;
574
1.06M
    if (mem->gs_lib_ctx->client_check_file_permission != NULL) {
575
1.06M
        code = mem->gs_lib_ctx->client_check_file_permission(mem, fname, len, permission);
576
1.06M
    }
577
1.06M
    return code;
578
1.06M
}
579
580
static void
581
rewrite_percent_specifiers(char *s)
582
9.86k
{
583
9.86k
    char *match_start;
584
585
9.86k
    while (*s)
586
9.86k
    {
587
9.86k
        int flags;
588
        /* Find a % */
589
98.6k
        while (*s && *s != '%')
590
88.7k
            s++;
591
9.86k
        if (*s == 0)
592
9.86k
            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
9.86k
}
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
9.86k
{
658
9.86k
    char f[gp_file_name_sizeof];
659
9.86k
    int code;
660
661
    /* Be sure the string copy will fit */
662
9.86k
    if (strlen(fname) >= gp_file_name_sizeof)
663
0
        return gs_error_rangecheck;
664
9.86k
    strcpy(f, fname);
665
    /* Try to rewrite any %d (or similar) in the string */
666
9.86k
    rewrite_percent_specifiers(f);
667
668
9.86k
    code = gs_add_control_path(mem, gs_permit_file_control, f);
669
9.86k
    if (code < 0)
670
0
        return code;
671
9.86k
    return gs_add_control_path(mem, gs_permit_file_writing, f);
672
9.86k
}
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.37M
{
715
1.37M
    return gs_add_control_path_len_flags(mem, type, path, len, 0);
716
1.37M
}
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.41M
{
721
1.41M
    gs_path_control_set_t *control;
722
1.41M
    unsigned int n, i;
723
1.41M
    gs_lib_ctx_core_t *core;
724
1.41M
    char *buffer;
725
1.41M
    uint rlen;
726
727
1.41M
    if (path == NULL || len == 0)
728
0
        return 0;
729
730
1.41M
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
731
1.41M
        (core = mem->gs_lib_ctx->core) == NULL)
732
0
        return gs_error_unknownerror;
733
734
1.41M
    switch(type) {
735
1.33M
        case gs_permit_file_reading:
736
1.33M
            control = &core->permit_reading;
737
1.33M
            break;
738
44.6k
        case gs_permit_file_writing:
739
44.6k
            control = &core->permit_writing;
740
44.6k
            break;
741
34.7k
        case gs_permit_file_control:
742
34.7k
            control = &core->permit_control;
743
34.7k
            break;
744
0
        default:
745
0
            return gs_error_rangecheck;
746
1.41M
    }
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.41M
    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.41M
    else {
760
1.41M
        rlen = len + 1;
761
762
1.41M
        buffer = (char *)gs_alloc_bytes(core->memory, rlen, "gs_add_control_path_len");
763
1.41M
        if (buffer == NULL)
764
0
            return gs_error_VMerror;
765
766
1.41M
        if (gp_file_name_reduce(path, (uint)len, buffer, &rlen) != gp_combine_success)
767
0
            return gs_error_invalidfileaccess;
768
1.41M
        buffer[rlen] = 0;
769
1.41M
    }
770
771
1.41M
    n = control->num;
772
12.4M
    for (i = 0; i < n; i++)
773
12.0M
    {
774
12.0M
        if (strncmp(control->entry[i].path, buffer, rlen) == 0 &&
775
12.0M
            control->entry[i].path[rlen] == 0) {
776
1.03M
            gs_free_object(core->memory, buffer, "gs_add_control_path_len");
777
1.03M
            return 0; /* Already there! */
778
1.03M
        }
779
12.0M
    }
780
781
380k
    if (control->num == control->max) {
782
59.1k
        gs_path_control_entry_t *p;
783
784
59.1k
        n = control->max * 2;
785
59.1k
        if (n == 0) {
786
29.5k
            n = 4;
787
29.5k
            p = (gs_path_control_entry_t *)gs_alloc_bytes(core->memory, sizeof(*p)*n, "gs_lib_ctx(entries)");
788
29.5k
        } else
789
29.5k
            p = (gs_path_control_entry_t *)gs_resize_object(core->memory, control->entry, sizeof(*p)*n, "gs_lib_ctx(entries)");
790
59.1k
        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
59.1k
        control->entry = p;
795
59.1k
        control->max = n;
796
59.1k
    }
797
798
380k
    n = control->num;
799
380k
    control->entry[n].path = buffer;
800
380k
    control->entry[n].path[len] = 0;
801
380k
    control->entry[n].flags = flags;
802
380k
    control->num++;
803
804
380k
    return 0;
805
380k
}
806
807
int
808
gs_add_control_path(const gs_memory_t *mem, gs_path_control_t type, const char *path)
809
29.5k
{
810
29.5k
    return gs_add_control_path_len_flags(mem, type, path, path ? strlen(path) : 0, 0);
811
29.5k
}
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
15.4k
{
816
15.4k
    return gs_add_control_path_len_flags(mem, type, path, path ? strlen(path) : 0, flags);
817
15.4k
}
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
29.5k
{
918
29.5k
    gs_path_control_set_t *control;
919
29.5k
    unsigned int n, in, out;
920
29.5k
    gs_lib_ctx_core_t *core;
921
922
29.5k
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
923
29.5k
        (core = mem->gs_lib_ctx->core) == NULL)
924
0
        return;
925
926
29.5k
    switch(type) {
927
9.86k
        case gs_permit_file_reading:
928
9.86k
            control = &core->permit_reading;
929
9.86k
            break;
930
9.86k
        case gs_permit_file_writing:
931
9.86k
            control = &core->permit_writing;
932
9.86k
            break;
933
9.86k
        case gs_permit_file_control:
934
9.86k
            control = &core->permit_control;
935
9.86k
            break;
936
0
        default:
937
0
            return;
938
29.5k
    }
939
940
29.5k
    n = control->num;
941
394k
    for (in = out = 0; in < n; in++) {
942
364k
        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
364k
            gs_free_object(core->memory, control->entry[in].path, "gs_lib_ctx(path)");
947
364k
    }
948
29.5k
    control->num = out;
949
29.5k
    if (out == 0) {
950
29.5k
        gs_free_object(core->memory, control->entry, "gs_lib_ctx(paths)");
951
29.5k
        control->entry = NULL;
952
29.5k
        control->max = 0;
953
29.5k
    }
954
29.5k
}
955
956
void
957
gs_purge_scratch_files(const gs_memory_t *mem)
958
9.86k
{
959
9.86k
    gs_path_control_set_t *control;
960
9.86k
    gs_path_control_t type;
961
9.86k
    int n, in, out;
962
9.86k
    gs_lib_ctx_core_t *core;
963
964
9.86k
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
965
9.86k
        (core = mem->gs_lib_ctx->core) == NULL)
966
0
        return;
967
968
39.4k
    for (type = gs_permit_file_reading; type <= gs_permit_file_control; type++)
969
29.5k
    {
970
29.5k
        switch(type) {
971
0
            default:
972
9.86k
            case gs_permit_file_reading:
973
9.86k
                control = &core->permit_reading;
974
9.86k
                break;
975
9.86k
            case gs_permit_file_writing:
976
9.86k
                control = &core->permit_writing;
977
9.86k
                break;
978
9.86k
            case gs_permit_file_control:
979
9.86k
                control = &core->permit_control;
980
9.86k
                break;
981
29.5k
        }
982
983
29.5k
        n = control->num;
984
409k
        for (in = out = 0; in < n; in++) {
985
380k
            if ((control->entry[in].flags & gs_path_control_flag_is_scratch_file) == 0) {
986
                /* Only purge scratch files! */
987
364k
                control->entry[out++] = control->entry[in];
988
364k
            } else {
989
15.4k
                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
5.15k
                    gp_unlink_impl(core->memory, control->entry[in].path);
994
5.15k
                }
995
15.4k
                gs_free_object(core->memory, control->entry[in].path, "gs_lib_ctx(path)");
996
15.4k
            }
997
380k
        }
998
29.5k
        control->num = out;
999
29.5k
        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
29.5k
    }
1005
9.86k
}
1006
1007
void
1008
gs_activate_path_control(gs_memory_t *mem, int enable)
1009
9.86k
{
1010
9.86k
    gs_lib_ctx_core_t *core;
1011
1012
9.86k
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
1013
9.86k
        (core = mem->gs_lib_ctx->core) == NULL)
1014
0
        return;
1015
1016
9.86k
    core->path_control_active = enable;
1017
9.86k
}
1018
1019
int
1020
gs_is_path_control_active(const gs_memory_t *mem)
1021
247k
{
1022
247k
    gs_lib_ctx_core_t *core;
1023
1024
247k
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
1025
247k
        (core = mem->gs_lib_ctx->core) == NULL)
1026
0
        return 0;
1027
1028
247k
    return core->path_control_active;
1029
247k
}
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
9.86k
{
1190
9.86k
    gs_lib_ctx_core_t *core = mem->gs_lib_ctx->core;
1191
9.86k
    uint i;
1192
1193
9.86k
    if (core == NULL)
1194
0
        return;
1195
1196
9.86k
    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
9.86k
    if (core->permitted_devices.devices != NULL)
1201
0
        gs_free_object(core->memory, core->permitted_devices.devices, "gs_purge_permitted_devices");
1202
1203
9.86k
    core->permitted_devices.max = core->permitted_devices.num = 0;
1204
9.86k
    core->permitted_devices.devices = NULL;
1205
9.86k
}
1206
1207
int
1208
gs_lib_ctx_stash_sanitized_arg(gs_lib_ctx_t *ctx, const char *arg)
1209
167k
{
1210
167k
    gs_lib_ctx_core_t *core;
1211
167k
    size_t len;
1212
167k
    const char *p;
1213
167k
    int elide = 0;
1214
1215
167k
    if (ctx == NULL || ctx->core == NULL || arg == NULL)
1216
0
        return 0;
1217
1218
    /* Sanitize arg */
1219
167k
    switch(*arg)
1220
167k
    {
1221
167k
    case '-':
1222
167k
        switch (arg[1])
1223
167k
        {
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
98.6k
        case 'd': /* We can let -dFoo=<whatever> through unchanged */
1249
98.6k
        case 'D': /* We can let -DFoo=<whatever> through unchanged */
1250
108k
        case 'r': /* We can let -r through unchanged */
1251
108k
        case 'Z': /* We can let -Z through unchanged */
1252
108k
        case 'g': /* We can let -g through unchanged */
1253
108k
        case 'P': /* We can let -P through unchanged */
1254
108k
        case '+': /* We can let -+ through unchanged */
1255
118k
        case '_': /* We can let -_ through unchanged */
1256
118k
        case 'u': /* We can let -u through unchanged */
1257
118k
        case 'q': /* We can let -q through unchanged */
1258
118k
            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
39.4k
        case 's':
1269
39.4k
        case 'S':
1270
            /* By default, we want to keep the key, but lose the value */
1271
39.4k
            p = arg+2;
1272
404k
            while (*p && *p != '=' && *p != '#')
1273
364k
                p++;
1274
39.4k
            if (*p == '=' || *p == '#')
1275
39.4k
                p++;
1276
39.4k
            if (*p == 0)
1277
0
                break; /* No value to elide */
1278
            /* Check for our whitelisted values here */
1279
39.4k
#define ARG_MATCHES(STR, ARG, LEN) \
1280
256k
    (strlen(STR) == LEN && !memcmp(STR, ARG, LEN))
1281
39.4k
            if (ARG_MATCHES("DEFAULTPAPERSIZE", arg+2, p-arg-3))
1282
0
                break;
1283
39.4k
            if (ARG_MATCHES("DEVICE", arg+2, p-arg-3))
1284
9.86k
                break;
1285
29.5k
            if (ARG_MATCHES("PAPERSIZE", arg+2, p-arg-3))
1286
0
                break;
1287
29.5k
            if (ARG_MATCHES("SUBSTFONT", arg+2, p-arg-3))
1288
0
                break;
1289
29.5k
            if (ARG_MATCHES("ColorConversionStrategy", arg+2, p-arg-3))
1290
0
                break;
1291
29.5k
            if (ARG_MATCHES("NupControl", arg+2, p-arg-3))
1292
0
                break;
1293
29.5k
            if (ARG_MATCHES("PageList", arg+2, p-arg-3))
1294
0
                break;
1295
29.5k
            if (ARG_MATCHES("ProcessColorModel", arg+2, p-arg-3))
1296
0
                break;
1297
29.5k
#undef ARG_MATCHES
1298
            /* Didn't match a whitelisted value, so elide it. */
1299
29.5k
            elide = 1;
1300
29.5k
            break;
1301
9.86k
        default:
1302
            /* Shouldn't happen, but elide it just in case */
1303
9.86k
            arg = "?";
1304
9.86k
            break;
1305
167k
        }
1306
167k
        break;
1307
167k
    case '@':
1308
        /* Shouldn't happen */
1309
0
    default:
1310
        /* Anything else should be elided */
1311
0
        arg = "?";
1312
0
        break;
1313
167k
    }
1314
1315
167k
    core = ctx->core;
1316
167k
    if (elide)
1317
29.5k
        len = p-arg;
1318
138k
    else
1319
138k
        len = strlen(arg);
1320
1321
167k
    if (core->arg_max == core->argc) {
1322
29.5k
        char **argv;
1323
29.5k
        int newlen = core->arg_max * 2;
1324
29.5k
        if (newlen == 0)
1325
0
            newlen = 4;
1326
29.5k
        argv = (char **)gs_alloc_bytes(ctx->core->memory, sizeof(char *) * newlen,
1327
29.5k
                                       "gs_lib_ctx_args");
1328
29.5k
        if (argv == NULL)
1329
0
            return gs_error_VMerror;
1330
29.5k
        if (core->argc > 0) {
1331
29.5k
            memcpy(argv, core->argv, sizeof(char *) * core->argc);
1332
29.5k
            gs_free_object(ctx->memory, core->argv, "gs_lib_ctx_args");
1333
29.5k
        }
1334
29.5k
        core->argv = argv;
1335
29.5k
        core->arg_max = newlen;
1336
29.5k
    }
1337
1338
167k
    core->argv[core->argc] = (char *)gs_alloc_bytes(ctx->core->memory, len+1+elide,
1339
167k
                                                    "gs_lib_ctx_arg");
1340
167k
    if (core->argv[core->argc] == NULL)
1341
0
        return gs_error_VMerror;
1342
167k
    memcpy(core->argv[core->argc], arg, len);
1343
167k
    if (elide) {
1344
29.5k
        core->argv[core->argc][len] = '?';
1345
29.5k
    }
1346
167k
    core->argv[core->argc][len+elide] = 0;
1347
167k
    core->argc++;
1348
1349
167k
    return 0;
1350
167k
}
1351
1352
int
1353
gs_lib_ctx_stash_exe(gs_lib_ctx_t *ctx, const char *arg)
1354
9.86k
{
1355
9.86k
    gs_lib_ctx_core_t *core;
1356
9.86k
    size_t len;
1357
9.86k
    const char *p, *word;
1358
9.86k
    const char *sep = gp_file_name_directory_separator();
1359
9.86k
    size_t seplen = strlen(sep);
1360
1361
9.86k
    if (ctx == NULL || ctx->core == NULL || arg == NULL)
1362
0
        return 0;
1363
1364
    /* Sanitize arg */
1365
9.86k
    p = arg;
1366
9.86k
    word = NULL;
1367
29.5k
    for (p = arg; *p; p++) {
1368
19.7k
        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
19.7k
    }
1377
9.86k
    len = p - (word ? word : arg) + 1;
1378
9.86k
    if (word)
1379
0
        len += 5;
1380
1381
9.86k
    core = ctx->core;
1382
9.86k
    if (core->arg_max == core->argc) {
1383
9.86k
        char **argv;
1384
9.86k
        int newlen = core->arg_max * 2;
1385
9.86k
        if (newlen == 0)
1386
9.86k
            newlen = 4;
1387
9.86k
        argv = (char **)gs_alloc_bytes(ctx->core->memory, sizeof(char *) * newlen,
1388
9.86k
                                       "gs_lib_ctx_args");
1389
9.86k
        if (argv == NULL)
1390
0
            return gs_error_VMerror;
1391
9.86k
        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
9.86k
        core->argv = argv;
1396
9.86k
        core->arg_max = newlen;
1397
9.86k
    }
1398
1399
9.86k
    core->argv[core->argc] = (char *)gs_alloc_bytes(ctx->core->memory, len,
1400
9.86k
                                                    "gs_lib_ctx_arg");
1401
9.86k
    if (core->argv[core->argc] == NULL)
1402
0
        return gs_error_VMerror;
1403
9.86k
    if (word)
1404
0
        strcpy(core->argv[core->argc], "path/");
1405
9.86k
    else
1406
9.86k
        core->argv[core->argc][0] = 0;
1407
9.86k
    strcat(core->argv[core->argc], word ? word : arg);
1408
9.86k
    core->argc++;
1409
1410
9.86k
    return 0;
1411
9.86k
}
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
}