Coverage Report

Created: 2026-09-14 07:34

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
147k
{
67
147k
    *in = stdin;
68
147k
    *out = stdout;
69
147k
    *err = stderr;
70
147k
}
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
789k
{
81
789k
    char *result;
82
789k
    gs_lib_ctx_t *p_ctx = mem_gc->gs_lib_ctx;
83
789k
    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
789k
    if (p_ctx->profiledir != NULL && strcmp(pname,DEFAULT_DIR_ICC) == 0) {
89
631k
        return 0;
90
631k
    }
91
158k
    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
158k
    result = (char*) gs_alloc_bytes(p_ctx_mem, dir_namelen+1,
102
158k
                                     "gs_lib_ctx_set_icc_directory");
103
158k
    if (result == NULL) {
104
0
        return gs_error_VMerror;
105
0
    }
106
158k
    strcpy(result, pname);
107
158k
    p_ctx->profiledir = result;
108
158k
    p_ctx->profiledir_len = dir_namelen;
109
158k
    return 0;
110
158k
}
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
158k
{
117
158k
    char *result;
118
158k
    gs_lib_ctx_t *p_ctx = mem->gs_lib_ctx;
119
158k
    gs_memory_t *ctx_mem = p_ctx->memory;
120
158k
    int code = 0;
121
122
158k
    result = (char *)gs_alloc_bytes(ctx_mem, list_str_len + 1,
123
158k
             "gs_lib_ctx_set_default_device_list");
124
125
158k
    if (result) {
126
158k
      gs_free_object(ctx_mem, p_ctx->default_device_list,
127
158k
                "gs_lib_ctx_set_default_device_list");
128
129
158k
      memcpy(result, dev_list_str, list_str_len);
130
158k
      result[list_str_len] = '\0';
131
158k
      p_ctx->default_device_list = result;
132
158k
    }
133
0
    else {
134
0
        code = gs_note_error(gs_error_VMerror);
135
0
    }
136
158k
    return code;
137
158k
}
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
474k
{
159
474k
  int code = 0;
160
161
474k
  *rp = gs_raw_alloc_struct_immovable(mem, &st_gc_root_t, "gs_lib_ctx_alloc_root_structure");
162
474k
  if (*rp == 0)
163
0
    code = gs_note_error(gs_error_VMerror);
164
165
474k
  return code;
166
474k
}
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
44.3M
{
175
44.3M
    FILE *f;
176
177
44.3M
    *file = gp_file_FILE_alloc(mem);
178
44.3M
    if (*file == NULL)
179
0
        return 0;
180
44.3M
    f = gp_fopen_impl(mem->non_gc_memory, fname, mode);
181
44.3M
    if (gp_file_FILE_set(*file, f, fclose)) {
182
44.1M
        *file = NULL;
183
44.1M
        return gs_error_VMerror;
184
44.1M
    }
185
203k
    return 0;
186
44.3M
}
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
262k
{
191
262k
    *file = gp_file_FILE_alloc(mem);
192
262k
    if (*file == NULL)
193
0
        return gs_error_VMerror;
194
262k
    if (gp_file_FILE_set(*file,
195
262k
                         gp_open_scratch_file_impl(mem,
196
262k
                                                   prefix,
197
262k
                                                   rfname,
198
262k
                                                   mode,
199
262k
                                                   rm),
200
262k
                                                   NULL)) {
201
0
        *file = NULL;
202
0
        return gs_error_invalidfileaccess;
203
0
    }
204
205
262k
    return 0;
206
262k
}
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
65.4k
{
211
65.4k
    FILE *f;
212
65.4k
    int (*close)(FILE *) = NULL;
213
214
65.4k
    *file = gp_file_FILE_alloc(mem);
215
65.4k
    if (*file == NULL)
216
0
        return gs_error_VMerror;
217
65.4k
    f = gp_open_printer_impl(mem->non_gc_memory, fname, &binary_mode, &close);
218
65.4k
    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
65.4k
    gp_setmode_binary_impl(f, binary_mode); /* lgtm [cpp/useless-expression] */
225
226
65.4k
    return 0;
227
65.4k
}
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
158k
{
261
158k
    gs_lib_ctx_t *pio = NULL;
262
158k
    gs_globals *globals;
263
264
    /* Check the non gc allocator is being passed in */
265
158k
    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
158k
    globals = gp_get_globals();
272
273
    /* Now it's safe to set this. */
274
158k
    gp_set_debug_mem_ptr(mem);
275
276
158k
    if (mem->gs_lib_ctx) /* one time initialization */
277
0
        return 0;
278
279
158k
    pio = (gs_lib_ctx_t*)gs_alloc_bytes_immovable(mem,
280
158k
                                                  sizeof(gs_lib_ctx_t),
281
158k
                                                  "gs_lib_ctx_init");
282
158k
    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
158k
    memset(pio, 0, sizeof(*pio));
288
289
158k
    if (ctx != NULL) {
290
11.0k
        pio->core = ctx->core;
291
11.0k
        gx_monitor_enter((gx_monitor_t *)(pio->core->monitor));
292
11.0k
        pio->core->refs++;
293
11.0k
        gx_monitor_leave((gx_monitor_t *)(pio->core->monitor));
294
147k
    } else {
295
147k
        pio->core = (gs_lib_ctx_core_t *)gs_alloc_bytes_immovable(mem,
296
147k
                                                                  sizeof(gs_lib_ctx_core_t),
297
147k
                                                                  "gs_lib_ctx_init(core)");
298
147k
        if (pio->core == NULL) {
299
0
            gs_free_object(mem, pio, "gs_lib_ctx_init");
300
0
            return -1;
301
0
        }
302
147k
        memset(pio->core, 0, sizeof(*pio->core));
303
147k
        pio->core->globals = globals;
304
147k
        pio->core->fs = (gs_fs_list_t *)gs_alloc_bytes_immovable(mem,
305
147k
                                                                 sizeof(gs_fs_list_t),
306
147k
                                                                 "gs_lib_ctx_init(gs_fs_list_t)");
307
147k
        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
147k
        pio->core->fs->fs.open_file = fs_file_open_file;
322
        /* The iodev will fill this in later, if pipes are enabled */
323
147k
        pio->core->fs->fs.open_pipe = NULL;
324
147k
        pio->core->fs->fs.open_scratch = fs_file_open_scratch;
325
147k
        pio->core->fs->fs.open_printer = fs_file_open_printer;
326
147k
        pio->core->fs->secret = NULL;
327
147k
        pio->core->fs->memory = mem;
328
147k
        pio->core->fs->next   = NULL;
329
330
147k
        pio->core->monitor = gx_monitor_alloc(mem);
331
147k
        if (pio->core->monitor == NULL)
332
0
            goto core_create_failed;
333
147k
        pio->core->refs = 1;
334
147k
        pio->core->memory = mem;
335
336
        /* Set the non-zero "shared" things */
337
147k
        gs_lib_ctx_get_real_stdio(&pio->core->fstdin, &pio->core->fstdout, &pio->core->fstderr );
338
147k
        pio->core->stdin_is_interactive = true;
339
        /* id's 1 through 4 are reserved for Device color spaces; see gscspace.h */
340
147k
        pio->core->gs_next_id = 5; /* Cloned contexts share the state */
341
        /* Set scanconverter to 1 (default) */
342
147k
        pio->core->scanconverter = GS_SCANCONVERTER_DEFAULT;
343
        /* Initialise the underlying CMS. */
344
147k
        pio->core->cms_context = gscms_create(mem);
345
147k
        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
147k
    }
357
358
    /* Now set the non zero/false/NULL things */
359
158k
    pio->memory               = mem;
360
361
    /* Need to set this before calling gs_lib_ctx_set_icc_directory. */
362
158k
    mem->gs_lib_ctx = pio;
363
    /* Initialize our default ICCProfilesDir */
364
158k
    pio->profiledir = NULL;
365
158k
    pio->profiledir_len = 0;
366
158k
    pio->icc_color_accuracy = MAX_COLOR_ACCURACY;
367
158k
    if (gs_lib_ctx_set_icc_directory(mem, DEFAULT_DIR_ICC, strlen(DEFAULT_DIR_ICC)) < 0)
368
0
      goto Failure;
369
370
158k
    if (gs_lib_ctx_set_default_device_list(mem, gs_dev_defaults,
371
158k
                                           strlen(gs_dev_defaults)) < 0)
372
0
        goto Failure;
373
374
    /* Initialise any lock required for the jpx codec */
375
158k
    if (sjpxd_create(mem))
376
0
        goto Failure;
377
378
158k
    pio->client_check_file_permission = NULL;
379
158k
    gp_get_realtime(pio->real_time_0);
380
381
158k
    if (gs_lib_ctx_alloc_root_structure(mem, &pio->name_table_root))
382
0
        goto Failure;
383
384
158k
    if (gs_lib_ctx_alloc_root_structure(mem, &pio->io_device_table_root))
385
0
        goto Failure;
386
387
158k
    if (gs_lib_ctx_alloc_root_structure(mem, &pio->font_dir_root))
388
0
        goto Failure;
389
158k
    if (gs_add_control_path(mem, gs_permit_file_writing, gp_null_file_name) < 0)
390
0
        goto Failure;
391
392
158k
    return 0;
393
394
0
Failure:
395
0
    gs_lib_ctx_fin(mem);
396
0
    return -1;
397
158k
}
398
399
static void remove_ctx_pointers(gs_memory_t *mem)
400
158k
{
401
158k
    mem->gs_lib_ctx = NULL;
402
158k
    if (mem->stable_memory && mem->stable_memory != mem)
403
0
        remove_ctx_pointers(mem->stable_memory);
404
158k
    if (mem->non_gc_memory && mem->non_gc_memory != mem)
405
0
        remove_ctx_pointers(mem->non_gc_memory);
406
158k
    if (mem->thread_safe_memory && mem->thread_safe_memory != mem)
407
0
        remove_ctx_pointers(mem->thread_safe_memory);
408
158k
}
409
410
void gs_lib_ctx_fin(gs_memory_t *mem)
411
158k
{
412
158k
    gs_lib_ctx_t *ctx;
413
158k
    gs_memory_t *ctx_mem;
414
158k
    int refs, i;
415
158k
    gs_fs_list_t *fs;
416
158k
    gs_callout_list_t *entry;
417
418
158k
    if (!mem || !mem->gs_lib_ctx)
419
0
        return;
420
421
158k
    ctx = mem->gs_lib_ctx;
422
158k
    ctx_mem = ctx->memory;
423
424
158k
    sjpxd_destroy(mem);
425
158k
    gs_free_object(ctx_mem, ctx->profiledir,
426
158k
        "gs_lib_ctx_fin");
427
428
158k
    gs_free_object(ctx_mem, ctx->default_device_list,
429
158k
                "gs_lib_ctx_fin");
430
431
158k
    gs_free_object(ctx_mem, ctx->name_table_root, "gs_lib_ctx_fin");
432
158k
    gs_free_object(ctx_mem, ctx->io_device_table_root, "gs_lib_ctx_fin");
433
158k
    gs_free_object(ctx_mem, ctx->font_dir_root, "gs_lib_ctx_fin");
434
435
158k
    gx_monitor_enter((gx_monitor_t *)(ctx->core->monitor));
436
158k
    refs = --ctx->core->refs;
437
158k
    gx_monitor_leave((gx_monitor_t *)(ctx->core->monitor));
438
158k
    if (refs == 0) {
439
147k
        gscms_destroy(ctx->core->cms_context);
440
147k
        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
147k
        gs_purge_scratch_files(ctx->core->memory);
445
147k
        gs_purge_control_paths(ctx->core->memory, gs_permit_file_reading);
446
147k
        gs_purge_control_paths(ctx->core->memory, gs_permit_file_writing);
447
147k
        gs_purge_control_paths(ctx->core->memory, gs_permit_file_control);
448
449
147k
        gs_purge_permitted_devices(ctx->core->memory);
450
451
147k
        fs = ctx->core->fs;
452
294k
        while (fs) {
453
147k
            gs_fs_list_t *next = fs->next;
454
147k
            gs_free_object(fs->memory, fs, "gs_lib_ctx_fin");
455
147k
            fs = next;
456
147k
        }
457
458
147k
        entry = ctx->core->callouts;
459
147k
        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.70M
        for (i = 0; i < ctx->core->argc; i++)
466
2.55M
            gs_free_object(ctx->core->memory, ctx->core->argv[i], "gs_lib_ctx_arg");
467
147k
        gs_free_object(ctx->core->memory, ctx->core->argv, "gs_lib_ctx_args");
468
469
147k
        gs_free_object(ctx->core->memory, ctx->core, "gs_lib_ctx_fin");
470
147k
    }
471
158k
    remove_ctx_pointers(ctx_mem);
472
473
158k
    gs_free_object(ctx_mem, ctx, "gs_lib_ctx_init");
474
158k
}
475
476
gs_lib_ctx_t *gs_lib_ctx_get_interp_instance(const gs_memory_t *mem)
477
739M
{
478
739M
    if (mem == NULL)
479
0
        return NULL;
480
739M
    return mem->gs_lib_ctx;
481
739M
}
482
483
void *gs_lib_ctx_get_cms_context( const gs_memory_t *mem )
484
164M
{
485
164M
    if (mem == NULL)
486
0
        return NULL;
487
164M
    return mem->gs_lib_ctx->core->cms_context;
488
164M
}
489
490
int gs_lib_ctx_get_act_on_uel( const gs_memory_t *mem )
491
146k
{
492
146k
    if (mem == NULL)
493
0
        return 0;
494
146k
    return mem->gs_lib_ctx->core->act_on_uel;
495
146k
}
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.30M
{
502
1.30M
    int code;
503
1.30M
    gs_lib_ctx_t *pio = mem->gs_lib_ctx;
504
1.30M
    gs_lib_ctx_core_t *core = pio->core;
505
506
1.30M
    if (len == 0)
507
0
        return 0;
508
1.30M
    if (core->stdout_is_redirected) {
509
1.28M
        if (core->stdout_to_stderr)
510
0
            return errwrite(mem, str, len);
511
1.28M
        code = gp_fwrite(str, 1, len, core->fstdout2);
512
1.28M
        gp_fflush(core->fstdout2);
513
1.28M
    } else if (core->stdout_fn) {
514
15.7k
        return (*core->stdout_fn)(core->std_caller_handle, str, len);
515
15.7k
    } else {
516
0
        code = fwrite(str, 1, len, core->fstdout);
517
0
        fflush(core->fstdout);
518
0
    }
519
1.28M
    return code;
520
1.30M
}
521
522
int errwrite(const gs_memory_t *mem, const char *str, int len)
523
512k
{
524
512k
    int code;
525
512k
    gs_lib_ctx_t *ctx;
526
512k
    gs_lib_ctx_core_t *core;
527
512k
    if (len == 0)
528
0
        return 0;
529
512k
    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
512k
    ctx = mem->gs_lib_ctx;
537
512k
    if (ctx == NULL)
538
0
      return 0;
539
512k
    core = ctx->core;
540
512k
    if (core->stderr_fn)
541
512k
        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
512k
}
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
9.99M
{
573
9.99M
    int code = 0;
574
9.99M
    if (mem->gs_lib_ctx->client_check_file_permission != NULL) {
575
9.34M
        code = mem->gs_lib_ctx->client_check_file_permission(mem, fname, len, permission);
576
9.34M
    }
577
9.99M
    return code;
578
9.99M
}
579
580
static void
581
rewrite_percent_specifiers(char *s)
582
181k
{
583
181k
    char *match_start;
584
585
181k
    while (*s)
586
181k
    {
587
181k
        int flags;
588
        /* Find a % */
589
2.66M
        while (*s && *s != '%')
590
2.48M
            s++;
591
181k
        if (*s == 0)
592
181k
            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
181k
}
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
164k
{
658
164k
    char f[gp_file_name_sizeof];
659
164k
    int code;
660
661
    /* Be sure the string copy will fit */
662
164k
    if (strlen(fname) >= gp_file_name_sizeof)
663
0
        return gs_error_rangecheck;
664
164k
    strcpy(f, fname);
665
    /* Try to rewrite any %d (or similar) in the string */
666
164k
    rewrite_percent_specifiers(f);
667
668
164k
    code = gs_add_control_path(mem, gs_permit_file_control, f);
669
164k
    if (code < 0)
670
0
        return code;
671
    /* Some file formats (eg TIFF) require the device to be able to read and write */
672
164k
    code = gs_add_control_path(mem, gs_permit_file_reading, f);
673
164k
    if (code < 0)
674
0
        return code;
675
164k
    return gs_add_control_path(mem, gs_permit_file_writing, f);
676
164k
}
677
678
int
679
gs_remove_outputfile_control_path(gs_memory_t *mem, const char *fname)
680
16.9k
{
681
16.9k
    char f[gp_file_name_sizeof];
682
16.9k
    int code;
683
684
    /* Be sure the string copy will fit */
685
16.9k
    if (strlen(fname) >= gp_file_name_sizeof)
686
0
        return gs_error_rangecheck;
687
16.9k
    strcpy(f, fname);
688
    /* Try to rewrite any %d (or similar) in the string */
689
16.9k
    rewrite_percent_specifiers(f);
690
691
16.9k
    code = gs_remove_control_path(mem, gs_permit_file_control, f);
692
16.9k
    if (code < 0)
693
0
        return code;
694
16.9k
    return gs_remove_control_path(mem, gs_permit_file_writing, f);
695
16.9k
}
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
19.4M
{
719
19.4M
    return gs_add_control_path_len_flags(mem, type, path, len, 0);
720
19.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
20.7M
{
725
20.7M
    gs_path_control_set_t *control;
726
20.7M
    unsigned int n, i;
727
20.7M
    gs_lib_ctx_core_t *core;
728
20.7M
    char *buffer;
729
20.7M
    uint rlen;
730
731
20.7M
    if (path == NULL || len == 0)
732
0
        return 0;
733
734
20.7M
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
735
20.7M
        (core = mem->gs_lib_ctx->core) == NULL)
736
0
        return gs_error_unknownerror;
737
738
20.7M
    switch(type) {
739
19.8M
        case gs_permit_file_reading:
740
19.8M
            control = &core->permit_reading;
741
19.8M
            break;
742
524k
        case gs_permit_file_writing:
743
524k
            control = &core->permit_writing;
744
524k
            break;
745
366k
        case gs_permit_file_control:
746
366k
            control = &core->permit_control;
747
366k
            break;
748
0
        default:
749
0
            return gs_error_rangecheck;
750
20.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
20.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
20.7M
    else {
764
20.7M
        rlen = len + 1;
765
766
20.7M
        buffer = (char *)gs_alloc_bytes(core->memory, rlen, "gs_add_control_path_len");
767
20.7M
        if (buffer == NULL)
768
0
            return gs_error_VMerror;
769
770
20.7M
        if (gp_file_name_reduce(path, (uint)len, buffer, &rlen) != gp_combine_success)
771
0
            return gs_error_invalidfileaccess;
772
20.7M
        buffer[rlen] = 0;
773
20.7M
    }
774
775
20.7M
    n = control->num;
776
184M
    for (i = 0; i < n; i++)
777
178M
    {
778
178M
        if (strncmp(control->entry[i].path, buffer, rlen) == 0 &&
779
15.3M
            control->entry[i].path[rlen] == 0) {
780
15.3M
            gs_free_object(core->memory, buffer, "gs_add_control_path_len");
781
15.3M
            return 0; /* Already there! */
782
15.3M
        }
783
178M
    }
784
785
5.38M
    if (control->num == control->max) {
786
979k
        gs_path_control_entry_t *p;
787
788
979k
        n = control->max * 2;
789
979k
        if (n == 0) {
790
441k
            n = 4;
791
441k
            p = (gs_path_control_entry_t *)gs_alloc_bytes(core->memory, sizeof(*p)*n, "gs_lib_ctx(entries)");
792
441k
        } else
793
537k
            p = (gs_path_control_entry_t *)gs_resize_object(core->memory, control->entry, sizeof(*p)*n, "gs_lib_ctx(entries)");
794
979k
        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
979k
        control->entry = p;
799
979k
        control->max = n;
800
979k
    }
801
802
5.38M
    n = control->num;
803
5.38M
    control->entry[n].path = buffer;
804
5.38M
    control->entry[n].path[len] = 0;
805
5.38M
    control->entry[n].flags = flags;
806
5.38M
    control->num++;
807
808
5.38M
    return 0;
809
5.38M
}
810
811
int
812
gs_add_control_path(const gs_memory_t *mem, gs_path_control_t type, const char *path)
813
662k
{
814
662k
    return gs_add_control_path_len_flags(mem, type, path, path ? strlen(path) : 0, 0);
815
662k
}
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
605k
{
820
605k
    return gs_add_control_path_len_flags(mem, type, path, path ? strlen(path) : 0, flags);
821
605k
}
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
651k
{
832
651k
    gs_path_control_set_t *control;
833
651k
    unsigned int n, i;
834
651k
    gs_lib_ctx_core_t *core;
835
651k
    char *buffer;
836
651k
    uint rlen;
837
838
651k
    if (path == NULL || len == 0)
839
0
        return 0;
840
841
651k
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
842
651k
        (core = mem->gs_lib_ctx->core) == NULL)
843
0
        return gs_error_unknownerror;
844
845
651k
    switch(type) {
846
213k
        case gs_permit_file_reading:
847
213k
            control = &core->permit_reading;
848
213k
            break;
849
218k
        case gs_permit_file_writing:
850
218k
            control = &core->permit_writing;
851
218k
            break;
852
218k
        case gs_permit_file_control:
853
218k
            control = &core->permit_control;
854
218k
            break;
855
0
        default:
856
0
            return gs_error_rangecheck;
857
651k
    }
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
651k
    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
651k
    else {
871
651k
        rlen = len+1;
872
873
651k
        buffer = (char *)gs_alloc_bytes(core->memory, rlen, "gs_remove_control_path_len");
874
651k
        if (buffer == NULL)
875
0
            return gs_error_VMerror;
876
877
651k
        if (gp_file_name_reduce(path, (uint)len, buffer, &rlen) != gp_combine_success)
878
0
            return gs_error_invalidfileaccess;
879
651k
        buffer[rlen] = 0;
880
651k
    }
881
882
651k
    n = control->num;
883
6.68M
    for (i = 0; i < n; i++) {
884
6.68M
        if (control->entry[i].flags == flags &&
885
1.70M
            strncmp(control->entry[i].path, buffer, len) == 0 &&
886
650k
            control->entry[i].path[len] == 0)
887
650k
            break;
888
6.68M
    }
889
651k
    gs_free_object(core->memory, buffer, "gs_remove_control_path_len");
890
651k
    if (i == n)
891
854
        return 0;
892
893
650k
    gs_free_object(core->memory, control->entry[i].path, "gs_lib_ctx(path)");
894
2.24M
    for (;i < n-1; i++)
895
1.59M
        control->entry[i] = control->entry[i+1];
896
650k
    control->num = n-1;
897
898
650k
    return 0;
899
651k
}
900
901
int
902
gs_remove_control_path(const gs_memory_t *mem, gs_path_control_t type, const char *path)
903
45.8k
{
904
45.8k
    if (path == NULL)
905
0
        return 0;
906
907
45.8k
    return gs_remove_control_path_len_flags(mem, type, path, strlen(path), 0);
908
45.8k
}
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
605k
{
913
605k
    if (path == NULL)
914
0
        return 0;
915
916
605k
    return gs_remove_control_path_len_flags(mem, type, path, strlen(path), flags);
917
605k
}
918
919
void
920
gs_purge_control_paths(const gs_memory_t *mem, gs_path_control_t type)
921
441k
{
922
441k
    gs_path_control_set_t *control;
923
441k
    unsigned int n, in, out;
924
441k
    gs_lib_ctx_core_t *core;
925
926
441k
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
927
441k
        (core = mem->gs_lib_ctx->core) == NULL)
928
0
        return;
929
930
441k
    switch(type) {
931
147k
        case gs_permit_file_reading:
932
147k
            control = &core->permit_reading;
933
147k
            break;
934
147k
        case gs_permit_file_writing:
935
147k
            control = &core->permit_writing;
936
147k
            break;
937
147k
        case gs_permit_file_control:
938
147k
            control = &core->permit_control;
939
147k
            break;
940
0
        default:
941
0
            return;
942
441k
    }
943
944
441k
    n = control->num;
945
5.17M
    for (in = out = 0; in < n; in++) {
946
4.73M
        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
4.73M
            gs_free_object(core->memory, control->entry[in].path, "gs_lib_ctx(path)");
951
4.73M
    }
952
441k
    control->num = out;
953
441k
    if (out == 0) {
954
441k
        gs_free_object(core->memory, control->entry, "gs_lib_ctx(paths)");
955
441k
        control->entry = NULL;
956
441k
        control->max = 0;
957
441k
    }
958
441k
}
959
960
void
961
gs_purge_scratch_files(const gs_memory_t *mem)
962
147k
{
963
147k
    gs_path_control_set_t *control;
964
147k
    gs_path_control_t type;
965
147k
    int n, in, out;
966
147k
    gs_lib_ctx_core_t *core;
967
968
147k
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
969
147k
        (core = mem->gs_lib_ctx->core) == NULL)
970
0
        return;
971
972
589k
    for (type = gs_permit_file_reading; type <= gs_permit_file_control; type++)
973
441k
    {
974
441k
        switch(type) {
975
0
            default:
976
147k
            case gs_permit_file_reading:
977
147k
                control = &core->permit_reading;
978
147k
                break;
979
147k
            case gs_permit_file_writing:
980
147k
                control = &core->permit_writing;
981
147k
                break;
982
147k
            case gs_permit_file_control:
983
147k
                control = &core->permit_control;
984
147k
                break;
985
441k
        }
986
987
441k
        n = control->num;
988
5.17M
        for (in = out = 0; in < n; in++) {
989
4.73M
            if ((control->entry[in].flags & gs_path_control_flag_is_scratch_file) == 0) {
990
                /* Only purge scratch files! */
991
4.73M
                control->entry[out++] = control->entry[in];
992
4.73M
            } 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
4.73M
        }
1002
441k
        control->num = out;
1003
441k
        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
441k
    }
1009
147k
}
1010
1011
void
1012
gs_activate_path_control(gs_memory_t *mem, int enable)
1013
146k
{
1014
146k
    gs_lib_ctx_core_t *core;
1015
1016
146k
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
1017
146k
        (core = mem->gs_lib_ctx->core) == NULL)
1018
0
        return;
1019
1020
146k
    core->path_control_active = enable;
1021
146k
}
1022
1023
int
1024
gs_is_path_control_active(const gs_memory_t *mem)
1025
4.12M
{
1026
4.12M
    gs_lib_ctx_core_t *core;
1027
1028
4.12M
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
1029
4.12M
        (core = mem->gs_lib_ctx->core) == NULL)
1030
0
        return 0;
1031
1032
4.12M
    return core->path_control_active;
1033
4.12M
}
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
147k
{
1194
147k
    gs_lib_ctx_core_t *core = mem->gs_lib_ctx->core;
1195
147k
    uint i;
1196
1197
147k
    if (core == NULL)
1198
0
        return;
1199
1200
147k
    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
147k
    if (core->permitted_devices.devices != NULL)
1205
0
        gs_free_object(core->memory, core->permitted_devices.devices, "gs_purge_permitted_devices");
1206
1207
147k
    core->permitted_devices.max = core->permitted_devices.num = 0;
1208
147k
    core->permitted_devices.devices = NULL;
1209
147k
}
1210
1211
int
1212
gs_lib_ctx_stash_sanitized_arg(gs_lib_ctx_t *ctx, const char *arg)
1213
2.39M
{
1214
2.39M
    gs_lib_ctx_core_t *core;
1215
2.39M
    size_t len;
1216
2.39M
    const char *p;
1217
2.39M
    int elide = 0;
1218
1219
2.39M
    if (ctx == NULL || ctx->core == NULL || arg == NULL)
1220
0
        return 0;
1221
1222
    /* Sanitize arg */
1223
2.39M
    switch(*arg)
1224
2.39M
    {
1225
2.39M
    case '-':
1226
2.39M
        switch (arg[1])
1227
2.39M
        {
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.40M
        case 'd': /* We can let -dFoo=<whatever> through unchanged */
1253
1.40M
        case 'D': /* We can let -DFoo=<whatever> through unchanged */
1254
1.55M
        case 'r': /* We can let -r through unchanged */
1255
1.55M
        case 'Z': /* We can let -Z through unchanged */
1256
1.55M
        case 'g': /* We can let -g through unchanged */
1257
1.55M
        case 'P': /* We can let -P through unchanged */
1258
1.55M
        case '+': /* We can let -+ through unchanged */
1259
1.68M
        case '_': /* We can let -_ through unchanged */
1260
1.68M
        case 'u': /* We can let -u through unchanged */
1261
1.68M
        case 'q': /* We can let -q through unchanged */
1262
1.68M
            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
575k
        case 's':
1273
575k
        case 'S':
1274
            /* By default, we want to keep the key, but lose the value */
1275
575k
            p = arg+2;
1276
5.84M
            while (*p && *p != '=' && *p != '#')
1277
5.27M
                p++;
1278
575k
            if (*p == '=' || *p == '#')
1279
575k
                p++;
1280
575k
            if (*p == 0)
1281
0
                break; /* No value to elide */
1282
            /* Check for our whitelisted values here */
1283
575k
#define ARG_MATCHES(STR, ARG, LEN) \
1284
3.65M
    (strlen(STR) == LEN && !memcmp(STR, ARG, LEN))
1285
575k
            if (ARG_MATCHES("DEFAULTPAPERSIZE", arg+2, p-arg-3))
1286
0
                break;
1287
575k
            if (ARG_MATCHES("DEVICE", arg+2, p-arg-3))
1288
158k
                break;
1289
417k
            if (ARG_MATCHES("PAPERSIZE", arg+2, p-arg-3))
1290
0
                break;
1291
417k
            if (ARG_MATCHES("SUBSTFONT", arg+2, p-arg-3))
1292
0
                break;
1293
417k
            if (ARG_MATCHES("ColorConversionStrategy", arg+2, p-arg-3))
1294
0
                break;
1295
417k
            if (ARG_MATCHES("NupControl", arg+2, p-arg-3))
1296
0
                break;
1297
417k
            if (ARG_MATCHES("PageList", arg+2, p-arg-3))
1298
0
                break;
1299
417k
            if (ARG_MATCHES("ProcessColorModel", arg+2, p-arg-3))
1300
0
                break;
1301
417k
#undef ARG_MATCHES
1302
            /* Didn't match a whitelisted value, so elide it. */
1303
417k
            elide = 1;
1304
417k
            break;
1305
136k
        default:
1306
            /* Shouldn't happen, but elide it just in case */
1307
136k
            arg = "?";
1308
136k
            break;
1309
2.39M
        }
1310
2.39M
        break;
1311
2.39M
    case '@':
1312
        /* Shouldn't happen */
1313
0
    default:
1314
        /* Anything else should be elided */
1315
0
        arg = "?";
1316
0
        break;
1317
2.39M
    }
1318
1319
2.39M
    core = ctx->core;
1320
2.39M
    if (elide)
1321
417k
        len = p-arg;
1322
1.98M
    else
1323
1.98M
        len = strlen(arg);
1324
1325
2.39M
    if (core->arg_max == core->argc) {
1326
428k
        char **argv;
1327
428k
        int newlen = core->arg_max * 2;
1328
428k
        if (newlen == 0)
1329
0
            newlen = 4;
1330
428k
        argv = (char **)gs_alloc_bytes(ctx->core->memory, sizeof(char *) * newlen,
1331
428k
                                       "gs_lib_ctx_args");
1332
428k
        if (argv == NULL)
1333
0
            return gs_error_VMerror;
1334
428k
        if (core->argc > 0) {
1335
428k
            memcpy(argv, core->argv, sizeof(char *) * core->argc);
1336
428k
            gs_free_object(ctx->memory, core->argv, "gs_lib_ctx_args");
1337
428k
        }
1338
428k
        core->argv = argv;
1339
428k
        core->arg_max = newlen;
1340
428k
    }
1341
1342
2.39M
    core->argv[core->argc] = (char *)gs_alloc_bytes(ctx->core->memory, len+1+elide,
1343
2.39M
                                                    "gs_lib_ctx_arg");
1344
2.39M
    if (core->argv[core->argc] == NULL)
1345
0
        return gs_error_VMerror;
1346
2.39M
    memcpy(core->argv[core->argc], arg, len);
1347
2.39M
    if (elide) {
1348
417k
        core->argv[core->argc][len] = '?';
1349
417k
    }
1350
2.39M
    core->argv[core->argc][len+elide] = 0;
1351
2.39M
    core->argc++;
1352
1353
2.39M
    return 0;
1354
2.39M
}
1355
1356
int
1357
gs_lib_ctx_stash_exe(gs_lib_ctx_t *ctx, const char *arg)
1358
158k
{
1359
158k
    gs_lib_ctx_core_t *core;
1360
158k
    size_t len;
1361
158k
    const char *p, *word;
1362
158k
    const char *sep = gp_file_name_directory_separator();
1363
158k
    size_t seplen = strlen(sep);
1364
1365
158k
    if (ctx == NULL || ctx->core == NULL || arg == NULL)
1366
0
        return 0;
1367
1368
    /* Sanitize arg */
1369
158k
    p = arg;
1370
158k
    word = NULL;
1371
518k
    for (p = arg; *p; p++) {
1372
360k
        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
360k
    }
1381
158k
    len = p - (word ? word : arg) + 1;
1382
158k
    if (word)
1383
0
        len += 5;
1384
1385
158k
    core = ctx->core;
1386
158k
    if (core->arg_max == core->argc) {
1387
147k
        char **argv;
1388
147k
        int newlen = core->arg_max * 2;
1389
147k
        if (newlen == 0)
1390
147k
            newlen = 4;
1391
147k
        argv = (char **)gs_alloc_bytes(ctx->core->memory, sizeof(char *) * newlen,
1392
147k
                                       "gs_lib_ctx_args");
1393
147k
        if (argv == NULL)
1394
0
            return gs_error_VMerror;
1395
147k
        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
147k
        core->argv = argv;
1400
147k
        core->arg_max = newlen;
1401
147k
    }
1402
1403
158k
    core->argv[core->argc] = (char *)gs_alloc_bytes(ctx->core->memory, len,
1404
158k
                                                    "gs_lib_ctx_arg");
1405
158k
    if (core->argv[core->argc] == NULL)
1406
0
        return gs_error_VMerror;
1407
158k
    if (word)
1408
0
        strcpy(core->argv[core->argc], "path/");
1409
158k
    else
1410
158k
        core->argv[core->argc][0] = 0;
1411
158k
    strcat(core->argv[core->argc], word ? word : arg);
1412
158k
    core->argc++;
1413
1414
158k
    return 0;
1415
158k
}
1416
1417
int gs_lib_ctx_get_args(gs_lib_ctx_t *ctx, const char * const **argv)
1418
33.7k
{
1419
33.7k
    gs_lib_ctx_core_t *core;
1420
1421
33.7k
    if (ctx == NULL || ctx->core == NULL || argv == NULL)
1422
0
        return 0;
1423
1424
33.7k
    core = ctx->core;
1425
33.7k
    *argv = (const char * const *)core->argv;
1426
33.7k
    return core->argc;
1427
33.7k
}
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
}