Coverage Report

Created: 2026-10-28 08:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/base/gslibctx.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 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
866k
{
81
866k
    char *result;
82
866k
    gs_lib_ctx_t *p_ctx = mem_gc->gs_lib_ctx;
83
866k
    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
866k
    if (p_ctx->profiledir != NULL && strcmp(pname,DEFAULT_DIR_ICC) == 0) {
89
688k
        return 0;
90
688k
    }
91
178k
    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
178k
    result = (char*) gs_alloc_bytes(p_ctx_mem, dir_namelen+1,
102
178k
                                     "gs_lib_ctx_set_icc_directory");
103
178k
    if (result == NULL) {
104
0
        return gs_error_VMerror;
105
0
    }
106
178k
    strcpy(result, pname);
107
178k
    p_ctx->profiledir = result;
108
178k
    p_ctx->profiledir_len = dir_namelen;
109
178k
    return 0;
110
178k
}
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
178k
{
117
178k
    char *result;
118
178k
    gs_lib_ctx_t *p_ctx = mem->gs_lib_ctx;
119
178k
    gs_memory_t *ctx_mem = p_ctx->memory;
120
178k
    int code = 0;
121
122
178k
    result = (char *)gs_alloc_bytes(ctx_mem, list_str_len + 1,
123
178k
             "gs_lib_ctx_set_default_device_list");
124
125
178k
    if (result) {
126
178k
      gs_free_object(ctx_mem, p_ctx->default_device_list,
127
178k
                "gs_lib_ctx_set_default_device_list");
128
129
178k
      memcpy(result, dev_list_str, list_str_len);
130
178k
      result[list_str_len] = '\0';
131
178k
      p_ctx->default_device_list = result;
132
178k
    }
133
0
    else {
134
0
        code = gs_note_error(gs_error_VMerror);
135
0
    }
136
178k
    return code;
137
178k
}
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
534k
{
159
534k
  int code = 0;
160
161
534k
  *rp = gs_raw_alloc_struct_immovable(mem, &st_gc_root_t, "gs_lib_ctx_alloc_root_structure");
162
534k
  if (*rp == 0)
163
0
    code = gs_note_error(gs_error_VMerror);
164
165
534k
  return code;
166
534k
}
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
47.4M
{
175
47.4M
    FILE *f;
176
177
47.4M
    *file = gp_file_FILE_alloc(mem);
178
47.4M
    if (*file == NULL)
179
0
        return 0;
180
47.4M
    f = gp_fopen_impl(mem->non_gc_memory, fname, mode);
181
47.4M
    if (gp_file_FILE_set(*file, f, fclose)) {
182
47.1M
        *file = NULL;
183
47.1M
        return gs_error_VMerror;
184
47.1M
    }
185
218k
    return 0;
186
47.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
264k
{
191
264k
    *file = gp_file_FILE_alloc(mem);
192
264k
    if (*file == NULL)
193
0
        return gs_error_VMerror;
194
264k
    if (gp_file_FILE_set(*file,
195
264k
                         gp_open_scratch_file_impl(mem,
196
264k
                                                   prefix,
197
264k
                                                   rfname,
198
264k
                                                   mode,
199
264k
                                                   rm),
200
264k
                                                   NULL)) {
201
0
        *file = NULL;
202
0
        return gs_error_invalidfileaccess;
203
0
    }
204
205
264k
    return 0;
206
264k
}
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
73.2k
{
211
73.2k
    FILE *f;
212
73.2k
    int (*close)(FILE *) = NULL;
213
214
73.2k
    *file = gp_file_FILE_alloc(mem);
215
73.2k
    if (*file == NULL)
216
0
        return gs_error_VMerror;
217
73.2k
    f = gp_open_printer_impl(mem->non_gc_memory, fname, &binary_mode, &close);
218
73.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
73.2k
    gp_setmode_binary_impl(f, binary_mode); /* lgtm [cpp/useless-expression] */
225
226
73.2k
    return 0;
227
73.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
178k
{
261
178k
    gs_lib_ctx_t *pio = NULL;
262
178k
    gs_globals *globals;
263
264
    /* Check the non gc allocator is being passed in */
265
178k
    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
178k
    globals = gp_get_globals();
272
273
    /* Now it's safe to set this. */
274
178k
    gp_set_debug_mem_ptr(mem);
275
276
178k
    if (mem->gs_lib_ctx) /* one time initialization */
277
0
        return 0;
278
279
178k
    pio = (gs_lib_ctx_t*)gs_alloc_bytes_immovable(mem,
280
178k
                                                  sizeof(gs_lib_ctx_t),
281
178k
                                                  "gs_lib_ctx_init");
282
178k
    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
178k
    memset(pio, 0, sizeof(*pio));
288
289
178k
    if (ctx != NULL) {
290
16.0k
        pio->core = ctx->core;
291
16.0k
        gx_monitor_enter((gx_monitor_t *)(pio->core->monitor));
292
16.0k
        pio->core->refs++;
293
16.0k
        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
178k
    pio->memory               = mem;
360
361
    /* Need to set this before calling gs_lib_ctx_set_icc_directory. */
362
178k
    mem->gs_lib_ctx = pio;
363
    /* Initialize our default ICCProfilesDir */
364
178k
    pio->profiledir = NULL;
365
178k
    pio->profiledir_len = 0;
366
178k
    pio->icc_color_accuracy = MAX_COLOR_ACCURACY;
367
178k
    if (gs_lib_ctx_set_icc_directory(mem, DEFAULT_DIR_ICC, strlen(DEFAULT_DIR_ICC)) < 0)
368
0
      goto Failure;
369
370
178k
    if (gs_lib_ctx_set_default_device_list(mem, gs_dev_defaults,
371
178k
                                           strlen(gs_dev_defaults)) < 0)
372
0
        goto Failure;
373
374
    /* Initialise any lock required for the jpx codec */
375
178k
    if (sjpxd_create(mem))
376
0
        goto Failure;
377
378
178k
    pio->client_check_file_permission = NULL;
379
178k
    gp_get_realtime(pio->real_time_0);
380
381
178k
    if (gs_lib_ctx_alloc_root_structure(mem, &pio->name_table_root))
382
0
        goto Failure;
383
384
178k
    if (gs_lib_ctx_alloc_root_structure(mem, &pio->io_device_table_root))
385
0
        goto Failure;
386
387
178k
    if (gs_lib_ctx_alloc_root_structure(mem, &pio->font_dir_root))
388
0
        goto Failure;
389
178k
    if (gs_add_control_path(mem, gs_permit_file_writing, gp_null_file_name) < 0)
390
0
        goto Failure;
391
392
178k
    return 0;
393
394
0
Failure:
395
0
    gs_lib_ctx_fin(mem);
396
0
    return -1;
397
178k
}
398
399
static void remove_ctx_pointers(gs_memory_t *mem)
400
178k
{
401
178k
    mem->gs_lib_ctx = NULL;
402
178k
    if (mem->stable_memory && mem->stable_memory != mem)
403
0
        remove_ctx_pointers(mem->stable_memory);
404
178k
    if (mem->non_gc_memory && mem->non_gc_memory != mem)
405
0
        remove_ctx_pointers(mem->non_gc_memory);
406
178k
    if (mem->thread_safe_memory && mem->thread_safe_memory != mem)
407
0
        remove_ctx_pointers(mem->thread_safe_memory);
408
178k
}
409
410
void gs_lib_ctx_fin(gs_memory_t *mem)
411
178k
{
412
178k
    gs_lib_ctx_t *ctx;
413
178k
    gs_memory_t *ctx_mem;
414
178k
    int refs, i;
415
178k
    gs_fs_list_t *fs;
416
178k
    gs_callout_list_t *entry;
417
418
178k
    if (!mem || !mem->gs_lib_ctx)
419
0
        return;
420
421
178k
    ctx = mem->gs_lib_ctx;
422
178k
    ctx_mem = ctx->memory;
423
424
178k
    sjpxd_destroy(mem);
425
178k
    gs_free_object(ctx_mem, ctx->profiledir,
426
178k
        "gs_lib_ctx_fin");
427
428
178k
    gs_free_object(ctx_mem, ctx->default_device_list,
429
178k
                "gs_lib_ctx_fin");
430
431
178k
    gs_free_object(ctx_mem, ctx->name_table_root, "gs_lib_ctx_fin");
432
178k
    gs_free_object(ctx_mem, ctx->io_device_table_root, "gs_lib_ctx_fin");
433
178k
    gs_free_object(ctx_mem, ctx->font_dir_root, "gs_lib_ctx_fin");
434
435
178k
    gx_monitor_enter((gx_monitor_t *)(ctx->core->monitor));
436
178k
    refs = --ctx->core->refs;
437
178k
    gx_monitor_leave((gx_monitor_t *)(ctx->core->monitor));
438
178k
    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
2.95M
        for (i = 0; i < ctx->core->argc; i++)
466
2.79M
            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
178k
    remove_ctx_pointers(ctx_mem);
472
473
178k
    gs_free_object(ctx_mem, ctx, "gs_lib_ctx_init");
474
178k
}
475
476
gs_lib_ctx_t *gs_lib_ctx_get_interp_instance(const gs_memory_t *mem)
477
820M
{
478
820M
    if (mem == NULL)
479
0
        return NULL;
480
820M
    return mem->gs_lib_ctx;
481
820M
}
482
483
void *gs_lib_ctx_get_cms_context( const gs_memory_t *mem )
484
177M
{
485
177M
    if (mem == NULL)
486
0
        return NULL;
487
177M
    return mem->gs_lib_ctx->core->cms_context;
488
177M
}
489
490
int gs_lib_ctx_get_act_on_uel( const gs_memory_t *mem )
491
161k
{
492
161k
    if (mem == NULL)
493
0
        return 0;
494
161k
    return mem->gs_lib_ctx->core->act_on_uel;
495
161k
}
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
1.67M
{
502
1.67M
    int code;
503
1.67M
    gs_lib_ctx_t *pio = mem->gs_lib_ctx;
504
1.67M
    gs_lib_ctx_core_t *core = pio->core;
505
506
1.67M
    if (len == 0)
507
0
        return 0;
508
1.67M
    if (core->stdout_is_redirected) {
509
1.65M
        if (core->stdout_to_stderr)
510
0
            return errwrite(mem, str, len);
511
1.65M
        code = gp_fwrite(str, 1, len, core->fstdout2);
512
1.65M
        gp_fflush(core->fstdout2);
513
1.65M
    } else if (core->stdout_fn) {
514
18.3k
        return (*core->stdout_fn)(core->std_caller_handle, str, len);
515
18.3k
    } else {
516
0
        code = fwrite(str, 1, len, core->fstdout);
517
0
        fflush(core->fstdout);
518
0
    }
519
1.65M
    return code;
520
1.67M
}
521
522
int errwrite(const gs_memory_t *mem, const char *str, int len)
523
532k
{
524
532k
    int code;
525
532k
    gs_lib_ctx_t *ctx;
526
532k
    gs_lib_ctx_core_t *core;
527
532k
    if (len == 0)
528
0
        return 0;
529
532k
    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
532k
    ctx = mem->gs_lib_ctx;
537
532k
    if (ctx == NULL)
538
0
      return 0;
539
532k
    core = ctx->core;
540
532k
    if (core->stderr_fn)
541
532k
        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
532k
}
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
10.9M
{
573
10.9M
    int code = 0;
574
10.9M
    if (mem->gs_lib_ctx->client_check_file_permission != NULL) {
575
9.97M
        code = mem->gs_lib_ctx->client_check_file_permission(mem, fname, len, permission);
576
9.97M
    }
577
10.9M
    return code;
578
10.9M
}
579
580
static void
581
rewrite_percent_specifiers(char *s)
582
197k
{
583
197k
    char *match_start;
584
585
197k
    while (*s)
586
197k
    {
587
197k
        int flags;
588
        /* Find a % */
589
2.87M
        while (*s && *s != '%')
590
2.67M
            s++;
591
197k
        if (*s == 0)
592
197k
            return;
593
242
        match_start = s;
594
242
        s++;
595
        /* Skip over flags (just one instance of any given flag, in any order) */
596
242
        flags = 0;
597
242
        while (*s) {
598
242
            if (*s == '-' && (flags & 1) == 0)
599
0
                flags |= 1;
600
242
            else if (*s == '+' && (flags & 2) == 0)
601
0
                flags |= 2;
602
242
            else if (*s == ' ' && (flags & 4) == 0)
603
0
                flags |= 4;
604
242
            else if (*s == '0' && (flags & 8) == 0)
605
0
                flags |= 8;
606
242
            else if (*s == '#' && (flags & 16) == 0)
607
0
                flags |= 16;
608
242
            else
609
242
                break;
610
0
            s++;
611
0
        }
612
        /* Skip over width */
613
242
        while (*s >= '0' && *s <= '9')
614
0
            s++;
615
        /* Skip over .precision */
616
242
        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
242
        if (*s == 'l')
623
0
            s++;
624
242
        if (*s == 'd' ||
625
242
            *s == 'i' ||
626
242
            *s == 'u' ||
627
242
            *s == 'o' ||
628
242
            *s == 'x' ||
629
242
            *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
242
        else if (*s == '%') {
639
242
            char *s0 = s;
640
58.5k
            while (*s0) {
641
58.3k
                *s0 = *(s0 + 1);
642
58.3k
                s0++;
643
58.3k
            }
644
242
        }
645
242
    }
646
197k
}
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
    /* Some file formats (eg TIFF) require the device to be able to read and write */
672
179k
    code = gs_add_control_path(mem, gs_permit_file_reading, f);
673
179k
    if (code < 0)
674
0
        return code;
675
179k
    return gs_add_control_path(mem, gs_permit_file_writing, f);
676
179k
}
677
678
int
679
gs_remove_outputfile_control_path(gs_memory_t *mem, const char *fname)
680
17.6k
{
681
17.6k
    char f[gp_file_name_sizeof];
682
17.6k
    int code;
683
684
    /* Be sure the string copy will fit */
685
17.6k
    if (strlen(fname) >= gp_file_name_sizeof)
686
0
        return gs_error_rangecheck;
687
17.6k
    strcpy(f, fname);
688
    /* Try to rewrite any %d (or similar) in the string */
689
17.6k
    rewrite_percent_specifiers(f);
690
691
17.6k
    code = gs_remove_control_path(mem, gs_permit_file_control, f);
692
17.6k
    if (code < 0)
693
0
        return code;
694
17.6k
    return gs_remove_control_path(mem, gs_permit_file_writing, f);
695
17.6k
}
696
697
int
698
gs_add_explicit_control_path(gs_memory_t *mem, const char *arg, gs_path_control_t control)
699
0
{
700
0
    char *p2, *p1 = (char *)arg;
701
0
    const char *lim;
702
0
    int code = 0;
703
704
0
    if (arg == NULL)
705
0
        return 0;
706
0
    lim = arg + strlen(arg);
707
0
    while (code >= 0 && p1 < lim && (p2 = strchr(p1, (int)gp_file_name_list_separator)) != NULL) {
708
0
        code = gs_add_control_path_len(mem, control, p1, (int)(p2 - p1));
709
0
        p1 = p2 + 1;
710
0
    }
711
0
    if (p1 < lim)
712
0
        code = gs_add_control_path_len(mem, control, p1, (int)(lim - p1));
713
0
    return code;
714
0
}
715
716
int
717
gs_add_control_path_len(const gs_memory_t *mem, gs_path_control_t type, const char *path, size_t len)
718
21.4M
{
719
21.4M
    return gs_add_control_path_len_flags(mem, type, path, len, 0);
720
21.4M
}
721
722
int
723
gs_add_control_path_len_flags(const gs_memory_t *mem, gs_path_control_t type, const char *path, size_t len, int flags)
724
22.7M
{
725
22.7M
    gs_path_control_set_t *control;
726
22.7M
    unsigned int n, i;
727
22.7M
    gs_lib_ctx_core_t *core;
728
22.7M
    char *buffer;
729
22.7M
    uint rlen;
730
731
22.7M
    if (path == NULL || len == 0)
732
0
        return 0;
733
734
22.7M
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
735
22.7M
        (core = mem->gs_lib_ctx->core) == NULL)
736
0
        return gs_error_unknownerror;
737
738
22.7M
    switch(type) {
739
21.8M
        case gs_permit_file_reading:
740
21.8M
            control = &core->permit_reading;
741
21.8M
            break;
742
562k
        case gs_permit_file_writing:
743
562k
            control = &core->permit_writing;
744
562k
            break;
745
384k
        case gs_permit_file_control:
746
384k
            control = &core->permit_control;
747
384k
            break;
748
0
        default:
749
0
            return gs_error_rangecheck;
750
22.7M
    }
751
752
    /* "%pipe%" do not follow the normal rules for path definitions, so we
753
       don't "reduce" them to avoid unexpected results
754
     */
755
22.7M
    if (path[0] == '|' || (len > 5 && memcmp(path, "%pipe", 5) == 0)) {
756
0
        buffer = (char *)gs_alloc_bytes(core->memory, len + 1, "gs_add_control_path_len");
757
0
        if (buffer == NULL)
758
0
            return gs_error_VMerror;
759
0
        memcpy(buffer, path, len);
760
0
        buffer[len] = 0;
761
0
        rlen = len;
762
0
    }
763
22.7M
    else {
764
22.7M
        rlen = len + 1;
765
766
22.7M
        buffer = (char *)gs_alloc_bytes(core->memory, rlen, "gs_add_control_path_len");
767
22.7M
        if (buffer == NULL)
768
0
            return gs_error_VMerror;
769
770
22.7M
        if (gp_file_name_reduce(path, (uint)len, buffer, &rlen) != gp_combine_success)
771
0
            return gs_error_invalidfileaccess;
772
22.7M
        buffer[rlen] = 0;
773
22.7M
    }
774
775
22.7M
    n = control->num;
776
201M
    for (i = 0; i < n; i++)
777
195M
    {
778
195M
        if (strncmp(control->entry[i].path, buffer, rlen) == 0 &&
779
16.8M
            control->entry[i].path[rlen] == 0) {
780
16.8M
            gs_free_object(core->memory, buffer, "gs_add_control_path_len");
781
16.8M
            return 0; /* Already there! */
782
16.8M
        }
783
195M
    }
784
785
5.87M
    if (control->num == control->max) {
786
1.06M
        gs_path_control_entry_t *p;
787
788
1.06M
        n = control->max * 2;
789
1.06M
        if (n == 0) {
790
486k
            n = 4;
791
486k
            p = (gs_path_control_entry_t *)gs_alloc_bytes(core->memory, sizeof(*p)*n, "gs_lib_ctx(entries)");
792
486k
        } else
793
578k
            p = (gs_path_control_entry_t *)gs_resize_object(core->memory, control->entry, sizeof(*p)*n, "gs_lib_ctx(entries)");
794
1.06M
        if (p == NULL) {
795
0
            gs_free_object(core->memory, buffer, "gs_add_control_path_len");
796
0
            return gs_error_VMerror;
797
0
        }
798
1.06M
        control->entry = p;
799
1.06M
        control->max = n;
800
1.06M
    }
801
802
5.87M
    n = control->num;
803
5.87M
    control->entry[n].path = buffer;
804
5.87M
    control->entry[n].path[len] = 0;
805
5.87M
    control->entry[n].flags = flags;
806
5.87M
    control->num++;
807
808
5.87M
    return 0;
809
5.87M
}
810
811
int
812
gs_add_control_path(const gs_memory_t *mem, gs_path_control_t type, const char *path)
813
734k
{
814
734k
    return gs_add_control_path_len_flags(mem, type, path, path ? strlen(path) : 0, 0);
815
734k
}
816
817
int
818
gs_add_control_path_flags(const gs_memory_t *mem, gs_path_control_t type, const char *path, int flags)
819
614k
{
820
614k
    return gs_add_control_path_len_flags(mem, type, path, path ? strlen(path) : 0, flags);
821
614k
}
822
823
int
824
gs_remove_control_path_len(const gs_memory_t *mem, gs_path_control_t type, const char *path, size_t len)
825
0
{
826
0
    return gs_remove_control_path_len_flags(mem, type, path, len, 0);
827
0
}
828
829
int
830
gs_remove_control_path_len_flags(const gs_memory_t *mem, gs_path_control_t type, const char *path, size_t len, int flags)
831
666k
{
832
666k
    gs_path_control_set_t *control;
833
666k
    unsigned int n, i;
834
666k
    gs_lib_ctx_core_t *core;
835
666k
    char *buffer;
836
666k
    uint rlen;
837
838
666k
    if (path == NULL || len == 0)
839
0
        return 0;
840
841
666k
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
842
666k
        (core = mem->gs_lib_ctx->core) == NULL)
843
0
        return gs_error_unknownerror;
844
845
666k
    switch(type) {
846
221k
        case gs_permit_file_reading:
847
221k
            control = &core->permit_reading;
848
221k
            break;
849
222k
        case gs_permit_file_writing:
850
222k
            control = &core->permit_writing;
851
222k
            break;
852
222k
        case gs_permit_file_control:
853
222k
            control = &core->permit_control;
854
222k
            break;
855
0
        default:
856
0
            return gs_error_rangecheck;
857
666k
    }
858
859
    /* "%pipe%" do not follow the normal rules for path definitions, so we
860
       don't "reduce" them to avoid unexpected results
861
     */
862
666k
    if (path[0] == '|' || (len > 5 && memcmp(path, "%pipe", 5) == 0)) {
863
0
        buffer = (char *)gs_alloc_bytes(core->memory, len + 1, "gs_remove_control_path_len");
864
0
        if (buffer == NULL)
865
0
            return gs_error_VMerror;
866
0
        memcpy(buffer, path, len);
867
0
        buffer[len] = 0;
868
0
        rlen = len;
869
0
    }
870
666k
    else {
871
666k
        rlen = len+1;
872
873
666k
        buffer = (char *)gs_alloc_bytes(core->memory, rlen, "gs_remove_control_path_len");
874
666k
        if (buffer == NULL)
875
0
            return gs_error_VMerror;
876
877
666k
        if (gp_file_name_reduce(path, (uint)len, buffer, &rlen) != gp_combine_success)
878
0
            return gs_error_invalidfileaccess;
879
666k
        buffer[rlen] = 0;
880
666k
    }
881
882
666k
    n = control->num;
883
6.98M
    for (i = 0; i < n; i++) {
884
6.98M
        if (control->entry[i].flags == flags &&
885
1.85M
            strncmp(control->entry[i].path, buffer, len) == 0 &&
886
665k
            control->entry[i].path[len] == 0)
887
665k
            break;
888
6.98M
    }
889
666k
    gs_free_object(core->memory, buffer, "gs_remove_control_path_len");
890
666k
    if (i == n)
891
1.00k
        return 0;
892
893
665k
    gs_free_object(core->memory, control->entry[i].path, "gs_lib_ctx(path)");
894
2.21M
    for (;i < n-1; i++)
895
1.54M
        control->entry[i] = control->entry[i+1];
896
665k
    control->num = n-1;
897
898
665k
    return 0;
899
666k
}
900
901
int
902
gs_remove_control_path(const gs_memory_t *mem, gs_path_control_t type, const char *path)
903
52.3k
{
904
52.3k
    if (path == NULL)
905
0
        return 0;
906
907
52.3k
    return gs_remove_control_path_len_flags(mem, type, path, strlen(path), 0);
908
52.3k
}
909
910
int
911
gs_remove_control_path_flags(const gs_memory_t *mem, gs_path_control_t type, const char *path, int flags)
912
614k
{
913
614k
    if (path == NULL)
914
0
        return 0;
915
916
614k
    return gs_remove_control_path_len_flags(mem, type, path, strlen(path), flags);
917
614k
}
918
919
void
920
gs_purge_control_paths(const gs_memory_t *mem, gs_path_control_t type)
921
486k
{
922
486k
    gs_path_control_set_t *control;
923
486k
    unsigned int n, in, out;
924
486k
    gs_lib_ctx_core_t *core;
925
926
486k
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
927
486k
        (core = mem->gs_lib_ctx->core) == NULL)
928
0
        return;
929
930
486k
    switch(type) {
931
162k
        case gs_permit_file_reading:
932
162k
            control = &core->permit_reading;
933
162k
            break;
934
162k
        case gs_permit_file_writing:
935
162k
            control = &core->permit_writing;
936
162k
            break;
937
162k
        case gs_permit_file_control:
938
162k
            control = &core->permit_control;
939
162k
            break;
940
0
        default:
941
0
            return;
942
486k
    }
943
944
486k
    n = control->num;
945
5.69M
    for (in = out = 0; in < n; in++) {
946
5.21M
        if (control->entry[in].flags & gs_path_control_flag_is_scratch_file) {
947
            /* Don't purge scratch files! */
948
0
            control->entry[out++] = control->entry[in];
949
0
        } else
950
5.21M
            gs_free_object(core->memory, control->entry[in].path, "gs_lib_ctx(path)");
951
5.21M
    }
952
486k
    control->num = out;
953
486k
    if (out == 0) {
954
486k
        gs_free_object(core->memory, control->entry, "gs_lib_ctx(paths)");
955
486k
        control->entry = NULL;
956
486k
        control->max = 0;
957
486k
    }
958
486k
}
959
960
void
961
gs_purge_scratch_files(const gs_memory_t *mem)
962
162k
{
963
162k
    gs_path_control_set_t *control;
964
162k
    gs_path_control_t type;
965
162k
    int n, in, out;
966
162k
    gs_lib_ctx_core_t *core;
967
968
162k
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
969
162k
        (core = mem->gs_lib_ctx->core) == NULL)
970
0
        return;
971
972
648k
    for (type = gs_permit_file_reading; type <= gs_permit_file_control; type++)
973
486k
    {
974
486k
        switch(type) {
975
0
            default:
976
162k
            case gs_permit_file_reading:
977
162k
                control = &core->permit_reading;
978
162k
                break;
979
162k
            case gs_permit_file_writing:
980
162k
                control = &core->permit_writing;
981
162k
                break;
982
162k
            case gs_permit_file_control:
983
162k
                control = &core->permit_control;
984
162k
                break;
985
486k
        }
986
987
486k
        n = control->num;
988
5.69M
        for (in = out = 0; in < n; in++) {
989
5.21M
            if ((control->entry[in].flags & gs_path_control_flag_is_scratch_file) == 0) {
990
                /* Only purge scratch files! */
991
5.21M
                control->entry[out++] = control->entry[in];
992
5.21M
            } else {
993
0
                if (type == gs_permit_file_reading) {
994
                    /* Call gp_unlink_impl, as we don't want gp_unlink
995
                     * to go looking in the lists we are currently
996
                     * manipulating! */
997
0
                    gp_unlink_impl(core->memory, control->entry[in].path);
998
0
                }
999
0
                gs_free_object(core->memory, control->entry[in].path, "gs_lib_ctx(path)");
1000
0
            }
1001
5.21M
        }
1002
486k
        control->num = out;
1003
486k
        if (out == 0) {
1004
0
            gs_free_object(core->memory, control->entry, "gs_lib_ctx(paths)");
1005
0
            control->entry = NULL;
1006
0
            control->max = 0;
1007
0
        }
1008
486k
    }
1009
162k
}
1010
1011
void
1012
gs_activate_path_control(gs_memory_t *mem, int enable)
1013
161k
{
1014
161k
    gs_lib_ctx_core_t *core;
1015
1016
161k
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
1017
161k
        (core = mem->gs_lib_ctx->core) == NULL)
1018
0
        return;
1019
1020
161k
    core->path_control_active = enable;
1021
161k
}
1022
1023
int
1024
gs_is_path_control_active(const gs_memory_t *mem)
1025
4.55M
{
1026
4.55M
    gs_lib_ctx_core_t *core;
1027
1028
4.55M
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
1029
4.55M
        (core = mem->gs_lib_ctx->core) == NULL)
1030
0
        return 0;
1031
1032
4.55M
    return core->path_control_active;
1033
4.55M
}
1034
1035
int
1036
gs_add_fs(const gs_memory_t *mem,
1037
                gs_fs_t     *fs,
1038
                void        *secret)
1039
0
{
1040
0
    gs_fs_list_t *fsl;
1041
0
    gs_lib_ctx_core_t *core;
1042
1043
0
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
1044
0
        (core = mem->gs_lib_ctx->core) == NULL)
1045
0
        return gs_error_unknownerror;
1046
1047
0
    fsl = (gs_fs_list_t *)gs_alloc_bytes_immovable(mem->non_gc_memory,
1048
0
                                                   sizeof(gs_fs_list_t),
1049
0
                                                   "gs_fs_list_t");
1050
0
    if (fsl == NULL)
1051
0
        return gs_error_VMerror;
1052
0
    fsl->fs      = *fs;
1053
0
    fsl->secret  = secret;
1054
0
    fsl->memory  = mem->non_gc_memory;
1055
0
    fsl->next    = core->fs;
1056
0
    core->fs     = fsl;
1057
1058
0
    return 0;
1059
0
}
1060
1061
void
1062
gs_remove_fs(const gs_memory_t *mem,
1063
                   gs_fs_t     *rfs,
1064
                   void        *secret)
1065
0
{
1066
0
    gs_fs_list_t **pfs;
1067
0
    gs_lib_ctx_core_t *core;
1068
1069
0
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
1070
0
        (core = mem->gs_lib_ctx->core) == NULL)
1071
0
        return;
1072
1073
0
    pfs = &core->fs;
1074
0
    while (*pfs)
1075
0
    {
1076
0
        gs_fs_list_t *fs = *pfs;
1077
0
        if (fs->fs.open_file == rfs->open_file &&
1078
0
            fs->fs.open_pipe == rfs->open_pipe &&
1079
0
            fs->fs.open_scratch == rfs->open_scratch &&
1080
0
            fs->fs.open_printer == rfs->open_printer &&
1081
0
            fs->secret == secret) {
1082
0
            *pfs = fs->next;
1083
0
            gs_free_object(fs->memory, fs, "gs_fs_t");
1084
0
        } else
1085
0
            pfs = &(*pfs)->next;
1086
0
    }
1087
0
}
1088
1089
static int gs_add_device_control(gs_memory_t *mem, char *device, int len)
1090
0
{
1091
0
    gs_lib_ctx_core_t *core;
1092
0
    char *buffer;
1093
0
    uint rlen, n, i;
1094
1095
0
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
1096
0
        (core = mem->gs_lib_ctx->core) == NULL)
1097
0
        return gs_error_unknownerror;
1098
1099
0
    rlen = len + 1;
1100
1101
0
    buffer = (char *)gs_alloc_bytes(core->memory, rlen, "gs_add_device");
1102
0
    if (buffer == NULL)
1103
0
        return gs_error_VMerror;
1104
1105
0
    memcpy(buffer, device, len);
1106
0
    buffer[len] = 0;
1107
1108
0
    n = core->permitted_devices.num;
1109
0
    for (i = 0; i < n; i++)
1110
0
    {
1111
0
        if (strlen(core->permitted_devices.devices[i]) == len && strncmp(core->permitted_devices.devices[i], buffer, len) == 0) {
1112
0
            gs_free_object(core->memory, buffer, "gs_add_device");
1113
0
            return 0; /* Already there! */
1114
0
        }
1115
0
    }
1116
1117
0
    if (core->permitted_devices.num == core->permitted_devices.max) {
1118
0
        char **table;
1119
1120
0
        n = core->permitted_devices.max * 2;
1121
0
        if (n == 0) {
1122
0
            n = 2;
1123
0
            table = (char **)gs_alloc_bytes(core->memory, sizeof(char *) * n, "gs_add_device_control");
1124
0
            if (table == NULL) {
1125
0
                gs_free_object(core->memory, buffer, "gs_add_device");
1126
0
                return_error(gs_error_VMerror);
1127
0
            }
1128
0
            memset(table, 0x00, sizeof(char *) * n);
1129
0
        } else {
1130
0
            table = (char **)gs_resize_object(core->memory, core->permitted_devices.devices,sizeof(char *) * n, "gs_add_device_control");
1131
0
            if (table == NULL) {
1132
0
                gs_free_object(core->memory, buffer, "gs_add_device");
1133
0
                return_error(gs_error_VMerror);
1134
0
            }
1135
0
            memset(table + core->permitted_devices.max, 0x00, core->permitted_devices.max * sizeof(char *));
1136
0
        }
1137
0
        core->permitted_devices.devices = table;
1138
0
        core->permitted_devices.max = n;
1139
0
    }
1140
0
    n = core->permitted_devices.num;
1141
0
    core->permitted_devices.devices[n] = buffer;
1142
0
    core->permitted_devices.num++;
1143
1144
0
    return 0;
1145
0
}
1146
1147
int
1148
gs_check_device_permission (gs_memory_t *mem, const char *dname, const int len)
1149
0
{
1150
0
    if (mem->gs_lib_ctx->core->permitted_devices.num != 0) {
1151
0
        int i;
1152
0
        char *permit_name = NULL;
1153
1154
0
        for (i=0;i < mem->gs_lib_ctx->core->permitted_devices.num; i++) {
1155
0
            permit_name = mem->gs_lib_ctx->core->permitted_devices.devices[i];
1156
1157
            /* Allow * as a wildcard */
1158
0
            if (permit_name != NULL && strlen(permit_name) == 1 && permit_name[0] == '*')
1159
0
                break;
1160
1161
0
            if (permit_name != NULL && strlen(permit_name) == len &&
1162
0
                strncmp(permit_name, dname, len) == 0)
1163
0
                break;
1164
0
        }
1165
0
        if (i >= mem->gs_lib_ctx->core->permitted_devices.num)
1166
0
            return 0;
1167
0
        return 1;
1168
0
    }
1169
0
    return 0;
1170
0
}
1171
1172
int
1173
gs_add_explicit_permitted_device(gs_memory_t *mem, const char *arg)
1174
0
{
1175
0
    char *p2, *p1 = (char *)arg;
1176
0
    const char *lim;
1177
0
    int code = 0;
1178
1179
0
    if (arg == NULL)
1180
0
        return 0;
1181
0
    lim = arg + strlen(arg);
1182
0
    while (code >= 0 && p1 < lim && (p2 = strchr(p1, gp_file_name_list_separator)) != NULL) {
1183
0
        code = gs_add_device_control(mem, p1, (int)(p2 - p1));
1184
0
        p1 = p2 + 1;
1185
0
    }
1186
0
    if (p1 < lim)
1187
0
        code = gs_add_device_control(mem, p1, (int)(lim - p1));
1188
0
    return code;
1189
0
}
1190
1191
static void
1192
gs_purge_permitted_devices(const gs_memory_t *mem)
1193
162k
{
1194
162k
    gs_lib_ctx_core_t *core = mem->gs_lib_ctx->core;
1195
162k
    uint i;
1196
1197
162k
    if (core == NULL)
1198
0
        return;
1199
1200
162k
    for (i=0;i < core->permitted_devices.max;i++) {
1201
0
        if (core->permitted_devices.devices[i] != NULL)
1202
0
            gs_free_object(core->memory, core->permitted_devices.devices[i], "gs_purge_permitted_devices");
1203
0
    }
1204
162k
    if (core->permitted_devices.devices != NULL)
1205
0
        gs_free_object(core->memory, core->permitted_devices.devices, "gs_purge_permitted_devices");
1206
1207
162k
    core->permitted_devices.max = core->permitted_devices.num = 0;
1208
162k
    core->permitted_devices.devices = NULL;
1209
162k
}
1210
1211
int
1212
gs_lib_ctx_stash_sanitized_arg(gs_lib_ctx_t *ctx, const char *arg)
1213
2.61M
{
1214
2.61M
    gs_lib_ctx_core_t *core;
1215
2.61M
    size_t len;
1216
2.61M
    const char *p;
1217
2.61M
    int elide = 0;
1218
1219
2.61M
    if (ctx == NULL || ctx->core == NULL || arg == NULL)
1220
0
        return 0;
1221
1222
    /* Sanitize arg */
1223
2.61M
    switch(*arg)
1224
2.61M
    {
1225
2.61M
    case '-':
1226
2.61M
        switch (arg[1])
1227
2.61M
        {
1228
0
        case 0:   /* We can let - through unchanged */
1229
0
        case '-': /* Need to check for permitted file lists */
1230
            /* By default, we want to keep the key, but lose the value */
1231
0
            p = arg+2;
1232
0
            while (*p && *p != '=' && *p != '#')
1233
0
                p++;
1234
0
            if (*p == '=' || *p == '#')
1235
0
                p++;
1236
0
            if (*p == 0)
1237
0
                break; /* No value to elide */
1238
            /* Check for our blocked values here */
1239
0
#define ARG_MATCHES(STR, ARG, LEN) \
1240
0
    (strlen(STR) == LEN && !memcmp(STR, ARG, LEN))
1241
0
            if (ARG_MATCHES("permit-file-read", arg+2, p-arg-3))
1242
0
                elide=1;
1243
0
            if (ARG_MATCHES("permit-file-write", arg+2, p-arg-3))
1244
0
                elide=1;
1245
0
            if (ARG_MATCHES("permit-file-control", arg+2, p-arg-3))
1246
0
                elide=1;
1247
0
            if (ARG_MATCHES("permit-file-all", arg+2, p-arg-3))
1248
0
                elide=1;
1249
0
#undef ARG_MATCHES
1250
            /* Didn't match a blocked value, so allow it. */
1251
0
            break;
1252
1.52M
        case 'd': /* We can let -dFoo=<whatever> through unchanged */
1253
1.52M
        case 'D': /* We can let -DFoo=<whatever> through unchanged */
1254
1.69M
        case 'r': /* We can let -r through unchanged */
1255
1.69M
        case 'Z': /* We can let -Z through unchanged */
1256
1.69M
        case 'g': /* We can let -g through unchanged */
1257
1.69M
        case 'P': /* We can let -P through unchanged */
1258
1.69M
        case '+': /* We can let -+ through unchanged */
1259
1.83M
        case '_': /* We can let -_ through unchanged */
1260
1.83M
        case 'u': /* We can let -u through unchanged */
1261
1.83M
        case 'q': /* We can let -q through unchanged */
1262
1.83M
            break;
1263
0
        case 'I': /* Let through the I, but hide anything else */
1264
0
        case 'f': /* Let through the I, but hide anything else */
1265
0
            if (arg[2] == 0)
1266
0
                break;
1267
0
            p = arg+2;
1268
0
            while (*p == 32)
1269
0
                p++;
1270
0
            elide = 1;
1271
0
            break;
1272
630k
        case 's':
1273
630k
        case 'S':
1274
            /* By default, we want to keep the key, but lose the value */
1275
630k
            p = arg+2;
1276
6.38M
            while (*p && *p != '=' && *p != '#')
1277
5.75M
                p++;
1278
630k
            if (*p == '=' || *p == '#')
1279
630k
                p++;
1280
630k
            if (*p == 0)
1281
0
                break; /* No value to elide */
1282
            /* Check for our whitelisted values here */
1283
630k
#define ARG_MATCHES(STR, ARG, LEN) \
1284
3.97M
    (strlen(STR) == LEN && !memcmp(STR, ARG, LEN))
1285
630k
            if (ARG_MATCHES("DEFAULTPAPERSIZE", arg+2, p-arg-3))
1286
0
                break;
1287
630k
            if (ARG_MATCHES("DEVICE", arg+2, p-arg-3))
1288
178k
                break;
1289
451k
            if (ARG_MATCHES("PAPERSIZE", arg+2, p-arg-3))
1290
0
                break;
1291
451k
            if (ARG_MATCHES("SUBSTFONT", arg+2, p-arg-3))
1292
0
                break;
1293
451k
            if (ARG_MATCHES("ColorConversionStrategy", arg+2, p-arg-3))
1294
0
                break;
1295
451k
            if (ARG_MATCHES("NupControl", arg+2, p-arg-3))
1296
0
                break;
1297
451k
            if (ARG_MATCHES("PageList", arg+2, p-arg-3))
1298
0
                break;
1299
451k
            if (ARG_MATCHES("ProcessColorModel", arg+2, p-arg-3))
1300
0
                break;
1301
451k
#undef ARG_MATCHES
1302
            /* Didn't match a whitelisted value, so elide it. */
1303
451k
            elide = 1;
1304
451k
            break;
1305
146k
        default:
1306
            /* Shouldn't happen, but elide it just in case */
1307
146k
            arg = "?";
1308
146k
            break;
1309
2.61M
        }
1310
2.61M
        break;
1311
2.61M
    case '@':
1312
        /* Shouldn't happen */
1313
0
    default:
1314
        /* Anything else should be elided */
1315
0
        arg = "?";
1316
0
        break;
1317
2.61M
    }
1318
1319
2.61M
    core = ctx->core;
1320
2.61M
    if (elide)
1321
451k
        len = p-arg;
1322
2.16M
    else
1323
2.16M
        len = strlen(arg);
1324
1325
2.61M
    if (core->arg_max == core->argc) {
1326
467k
        char **argv;
1327
467k
        int newlen = core->arg_max * 2;
1328
467k
        if (newlen == 0)
1329
0
            newlen = 4;
1330
467k
        argv = (char **)gs_alloc_bytes(ctx->core->memory, sizeof(char *) * newlen,
1331
467k
                                       "gs_lib_ctx_args");
1332
467k
        if (argv == NULL)
1333
0
            return gs_error_VMerror;
1334
467k
        if (core->argc > 0) {
1335
467k
            memcpy(argv, core->argv, sizeof(char *) * core->argc);
1336
467k
            gs_free_object(ctx->memory, core->argv, "gs_lib_ctx_args");
1337
467k
        }
1338
467k
        core->argv = argv;
1339
467k
        core->arg_max = newlen;
1340
467k
    }
1341
1342
2.61M
    core->argv[core->argc] = (char *)gs_alloc_bytes(ctx->core->memory, len+1+elide,
1343
2.61M
                                                    "gs_lib_ctx_arg");
1344
2.61M
    if (core->argv[core->argc] == NULL)
1345
0
        return gs_error_VMerror;
1346
2.61M
    memcpy(core->argv[core->argc], arg, len);
1347
2.61M
    if (elide) {
1348
451k
        core->argv[core->argc][len] = '?';
1349
451k
    }
1350
2.61M
    core->argv[core->argc][len+elide] = 0;
1351
2.61M
    core->argc++;
1352
1353
2.61M
    return 0;
1354
2.61M
}
1355
1356
int
1357
gs_lib_ctx_stash_exe(gs_lib_ctx_t *ctx, const char *arg)
1358
178k
{
1359
178k
    gs_lib_ctx_core_t *core;
1360
178k
    size_t len;
1361
178k
    const char *p, *word;
1362
178k
    const char *sep = gp_file_name_directory_separator();
1363
178k
    size_t seplen = strlen(sep);
1364
1365
178k
    if (ctx == NULL || ctx->core == NULL || arg == NULL)
1366
0
        return 0;
1367
1368
    /* Sanitize arg */
1369
178k
    p = arg;
1370
178k
    word = NULL;
1371
598k
    for (p = arg; *p; p++) {
1372
420k
        if (memcmp(sep, p, seplen) == 0) {
1373
0
            word = p+seplen;
1374
0
            p += seplen-1;
1375
0
        }
1376
#if defined(__WIN32__) || defined(__OS2__) || defined(METRO)
1377
        if (*p == '\\')
1378
            word = p+1;
1379
#endif
1380
420k
    }
1381
178k
    len = p - (word ? word : arg) + 1;
1382
178k
    if (word)
1383
0
        len += 5;
1384
1385
178k
    core = ctx->core;
1386
178k
    if (core->arg_max == core->argc) {
1387
162k
        char **argv;
1388
162k
        int newlen = core->arg_max * 2;
1389
162k
        if (newlen == 0)
1390
162k
            newlen = 4;
1391
162k
        argv = (char **)gs_alloc_bytes(ctx->core->memory, sizeof(char *) * newlen,
1392
162k
                                       "gs_lib_ctx_args");
1393
162k
        if (argv == NULL)
1394
0
            return gs_error_VMerror;
1395
162k
        if (core->argc > 0) {
1396
0
            memcpy(argv, core->argv, sizeof(char *) * core->argc);
1397
0
            gs_free_object(ctx->memory, core->argv, "gs_lib_ctx_args");
1398
0
        }
1399
162k
        core->argv = argv;
1400
162k
        core->arg_max = newlen;
1401
162k
    }
1402
1403
178k
    core->argv[core->argc] = (char *)gs_alloc_bytes(ctx->core->memory, len,
1404
178k
                                                    "gs_lib_ctx_arg");
1405
178k
    if (core->argv[core->argc] == NULL)
1406
0
        return gs_error_VMerror;
1407
178k
    if (word)
1408
0
        strcpy(core->argv[core->argc], "path/");
1409
178k
    else
1410
178k
        core->argv[core->argc][0] = 0;
1411
178k
    strcat(core->argv[core->argc], word ? word : arg);
1412
178k
    core->argc++;
1413
1414
178k
    return 0;
1415
178k
}
1416
1417
int gs_lib_ctx_get_args(gs_lib_ctx_t *ctx, const char * const **argv)
1418
32.5k
{
1419
32.5k
    gs_lib_ctx_core_t *core;
1420
1421
32.5k
    if (ctx == NULL || ctx->core == NULL || argv == NULL)
1422
0
        return 0;
1423
1424
32.5k
    core = ctx->core;
1425
32.5k
    *argv = (const char * const *)core->argv;
1426
32.5k
    return core->argc;
1427
32.5k
}
1428
1429
int gs_lib_ctx_register_callout(gs_memory_t *mem, gs_callout_fn fn, void *arg)
1430
0
{
1431
0
    gs_lib_ctx_core_t *core;
1432
0
    gs_callout_list_t *entry;
1433
1434
0
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
1435
0
        mem->gs_lib_ctx->core == NULL || fn == NULL)
1436
0
        return 0;
1437
1438
0
   core = mem->gs_lib_ctx->core;
1439
0
   entry = (gs_callout_list_t *)gs_alloc_bytes(core->memory,
1440
0
                                               sizeof(*entry),
1441
0
                                               "gs_callout_list_t");
1442
0
   if (entry == NULL)
1443
0
       return_error(gs_error_VMerror);
1444
0
   entry->next = core->callouts;
1445
0
   entry->callout = fn;
1446
0
   entry->handle = arg;
1447
0
   core->callouts = entry;
1448
1449
0
   return 0;
1450
0
}
1451
1452
void gs_lib_ctx_deregister_callout(gs_memory_t *mem, gs_callout_fn fn, void *arg)
1453
0
{
1454
0
    gs_lib_ctx_core_t *core;
1455
0
    gs_callout_list_t **entry;
1456
1457
0
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
1458
0
        mem->gs_lib_ctx->core == NULL || fn == NULL)
1459
0
        return;
1460
1461
0
   core = mem->gs_lib_ctx->core;
1462
0
   entry = &core->callouts;
1463
0
   while (*entry) {
1464
0
        if ((*entry)->callout == fn && (*entry)->handle == arg) {
1465
0
            gs_callout_list_t *next = (*entry)->next;
1466
0
            gs_free_object(core->memory, *entry, "gs_callout_list_t");
1467
0
            *entry = next;
1468
0
        } else {
1469
0
            entry = &(*entry)->next;
1470
0
        }
1471
0
   }
1472
0
}
1473
1474
int gs_lib_ctx_callout(gs_memory_t *mem, const char *dev_name,
1475
                       int id, int size, void *data)
1476
0
{
1477
0
    gs_lib_ctx_core_t *core;
1478
0
    gs_callout_list_t *entry;
1479
1480
0
    if (mem == NULL || mem->gs_lib_ctx == NULL || mem->gs_lib_ctx->core == NULL)
1481
0
        return -1;
1482
1483
0
    core = mem->gs_lib_ctx->core;
1484
0
    entry = core->callouts;
1485
0
    while (entry) {
1486
0
        int code = entry->callout(mem->gs_lib_ctx->top_of_system,
1487
0
                                  entry->handle, dev_name, id, size, data);
1488
0
        if (code >= 0)
1489
0
            return code;
1490
0
        if (code != gs_error_unknownerror)
1491
0
            return code;
1492
0
        entry = entry->next;
1493
0
    }
1494
0
    return -1;
1495
0
}
1496
1497
int gs_lib_ctx_nts_adjust(gs_memory_t *mem, int adjust)
1498
0
{
1499
0
    gs_lib_ctx_core_t *core;
1500
0
    int ret = 0;
1501
0
    gs_globals *globals;
1502
1503
0
    if (adjust == 0)
1504
0
        return 0;
1505
1506
0
    if (mem == NULL || mem->gs_lib_ctx == NULL || mem->gs_lib_ctx->core == NULL)
1507
0
        return_error(gs_error_unknownerror);
1508
1509
0
    core = mem->gs_lib_ctx->core;
1510
0
    globals = core->globals;
1511
0
    if (globals == NULL)
1512
0
        return 0; /* No globals means just once instance. Adjustment is pointless. */
1513
1514
0
    gp_global_lock(globals);
1515
0
    if (adjust > 0 && globals->non_threadsafe_count != 0)
1516
0
        ret = gs_error_unknownerror; /* We already have one non threadsafe device running. */
1517
0
    else if (adjust < 0 && globals->non_threadsafe_count == 0)
1518
0
        ret = gs_error_unknownerror; /* This indicates something has gone very wrong! */
1519
0
    else
1520
0
        globals->non_threadsafe_count += adjust;
1521
0
    gp_global_unlock(globals);
1522
1523
0
    if (ret)
1524
0
        ret = gs_note_error(ret);
1525
0
    return ret;
1526
0
}
1527
1528
void gs_globals_init(gs_globals *globals)
1529
22
{
1530
22
    memset(globals, 0, sizeof(*globals));
1531
22
}