Coverage Report

Created: 2022-04-16 11:23

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