Coverage Report

Created: 2025-06-24 07:01

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