Coverage Report

Created: 2022-10-31 07:00

/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
89.2k
{
64
89.2k
    *in = stdin;
65
89.2k
    *out = stdout;
66
89.2k
    *err = stderr;
67
89.2k
}
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
522k
{
78
522k
    char *result;
79
522k
    gs_lib_ctx_t *p_ctx = mem_gc->gs_lib_ctx;
80
522k
    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
522k
    if (p_ctx->profiledir != NULL && strcmp(pname,DEFAULT_DIR_ICC) == 0) {
86
178k
        return 0;
87
178k
    }
88
343k
    if (p_ctx->profiledir != NULL && p_ctx->profiledir_len > 0) {
89
254k
        if (strncmp(pname, p_ctx->profiledir, p_ctx->profiledir_len) == 0) {
90
165k
            return 0;
91
165k
        }
92
89.2k
        gs_free_object(p_ctx_mem, p_ctx->profiledir,
93
89.2k
                       "gs_lib_ctx_set_icc_directory");
94
89.2k
        p_ctx->profiledir = NULL;
95
89.2k
        p_ctx->profiledir_len = 0;
96
89.2k
    }
97
    /* User param string.  Must allocate in non-gc memory */
98
178k
    result = (char*) gs_alloc_bytes(p_ctx_mem, dir_namelen+1,
99
178k
                                     "gs_lib_ctx_set_icc_directory");
100
178k
    if (result == NULL) {
101
0
        return gs_error_VMerror;
102
0
    }
103
178k
    strcpy(result, pname);
104
178k
    p_ctx->profiledir = result;
105
178k
    p_ctx->profiledir_len = dir_namelen;
106
178k
    return 0;
107
178k
}
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
89.2k
{
114
89.2k
    char *result;
115
89.2k
    gs_lib_ctx_t *p_ctx = mem->gs_lib_ctx;
116
89.2k
    gs_memory_t *ctx_mem = p_ctx->memory;
117
89.2k
    int code = 0;
118
119
89.2k
    result = (char *)gs_alloc_bytes(ctx_mem, list_str_len + 1,
120
89.2k
             "gs_lib_ctx_set_default_device_list");
121
122
89.2k
    if (result) {
123
89.2k
      gs_free_object(ctx_mem, p_ctx->default_device_list,
124
89.2k
                "gs_lib_ctx_set_default_device_list");
125
126
89.2k
      memcpy(result, dev_list_str, list_str_len);
127
89.2k
      result[list_str_len] = '\0';
128
89.2k
      p_ctx->default_device_list = result;
129
89.2k
    }
130
0
    else {
131
0
        code = gs_note_error(gs_error_VMerror);
132
0
    }
133
89.2k
    return code;
134
89.2k
}
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
267k
{
156
267k
  int code = 0;
157
158
267k
  *rp = gs_raw_alloc_struct_immovable(mem, &st_gc_root_t, "gs_lib_ctx_alloc_root_structure");
159
267k
  if (*rp == 0)
160
0
    code = gs_note_error(gs_error_VMerror);
161
162
267k
  return code;
163
267k
}
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
21.2M
{
172
21.2M
    FILE *f;
173
174
21.2M
    *file = gp_file_FILE_alloc(mem);
175
21.2M
    if (*file == NULL)
176
0
        return 0;
177
21.2M
    f = gp_fopen_impl(mem->non_gc_memory, fname, mode);
178
21.2M
    if (gp_file_FILE_set(*file, f, fclose)) {
179
21.1M
        *file = NULL;
180
21.1M
        return gs_error_VMerror;
181
21.1M
    }
182
106k
    return 0;
183
21.2M
}
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
145k
{
188
145k
    *file = gp_file_FILE_alloc(mem);
189
145k
    if (*file == NULL)
190
0
        return gs_error_VMerror;
191
145k
    if (gp_file_FILE_set(*file,
192
145k
                         gp_open_scratch_file_impl(mem,
193
145k
                                                   prefix,
194
145k
                                                   rfname,
195
145k
                                                   mode,
196
145k
                                                   rm),
197
145k
                                                   NULL)) {
198
0
        *file = NULL;
199
0
        return gs_error_invalidfileaccess;
200
0
    }
201
202
145k
    return 0;
203
145k
}
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
34.9k
{
208
34.9k
    FILE *f;
209
34.9k
    int (*close)(FILE *) = NULL;
210
211
34.9k
    *file = gp_file_FILE_alloc(mem);
212
34.9k
    if (*file == NULL)
213
0
        return gs_error_VMerror;
214
34.9k
    f = gp_open_printer_impl(mem->non_gc_memory, fname, &binary_mode, &close);
215
34.9k
    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
34.9k
    gp_setmode_binary_impl(f, binary_mode); /* lgtm [cpp/useless-expression] */
222
223
34.9k
    return 0;
224
34.9k
}
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
89.2k
{
258
89.2k
    gs_lib_ctx_t *pio = NULL;
259
89.2k
    gs_globals *globals;
260
261
    /* Check the non gc allocator is being passed in */
262
89.2k
    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
89.2k
    globals = gp_get_globals();
269
270
    /* Now it's safe to set this. */
271
89.2k
    gp_set_debug_mem_ptr(mem);
272
273
89.2k
    if (mem->gs_lib_ctx) /* one time initialization */
274
0
        return 0;
275
276
89.2k
    pio = (gs_lib_ctx_t*)gs_alloc_bytes_immovable(mem,
277
89.2k
                                                  sizeof(gs_lib_ctx_t),
278
89.2k
                                                  "gs_lib_ctx_init");
279
89.2k
    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
89.2k
    memset(pio, 0, sizeof(*pio));
285
286
89.2k
    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
89.2k
    } else {
292
89.2k
        pio->core = (gs_lib_ctx_core_t *)gs_alloc_bytes_immovable(mem,
293
89.2k
                                                                  sizeof(gs_lib_ctx_core_t),
294
89.2k
                                                                  "gs_lib_ctx_init(core)");
295
89.2k
        if (pio->core == NULL) {
296
0
            gs_free_object(mem, pio, "gs_lib_ctx_init");
297
0
            return -1;
298
0
        }
299
89.2k
        memset(pio->core, 0, sizeof(*pio->core));
300
89.2k
        pio->core->globals = globals;
301
89.2k
        pio->core->fs = (gs_fs_list_t *)gs_alloc_bytes_immovable(mem,
302
89.2k
                                                                 sizeof(gs_fs_list_t),
303
89.2k
                                                                 "gs_lib_ctx_init(gs_fs_list_t)");
304
89.2k
        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
89.2k
        pio->core->fs->fs.open_file = fs_file_open_file;
319
        /* The iodev will fill this in later, if pipes are enabled */
320
89.2k
        pio->core->fs->fs.open_pipe = NULL;
321
89.2k
        pio->core->fs->fs.open_scratch = fs_file_open_scratch;
322
89.2k
        pio->core->fs->fs.open_printer = fs_file_open_printer;
323
89.2k
        pio->core->fs->secret = NULL;
324
89.2k
        pio->core->fs->memory = mem;
325
89.2k
        pio->core->fs->next   = NULL;
326
327
89.2k
        pio->core->monitor = gx_monitor_alloc(mem);
328
89.2k
        if (pio->core->monitor == NULL)
329
0
            goto core_create_failed;
330
89.2k
        pio->core->refs = 1;
331
89.2k
        pio->core->memory = mem;
332
333
        /* Set the non-zero "shared" things */
334
89.2k
        gs_lib_ctx_get_real_stdio(&pio->core->fstdin, &pio->core->fstdout, &pio->core->fstderr );
335
89.2k
        pio->core->stdin_is_interactive = true;
336
        /* id's 1 through 4 are reserved for Device color spaces; see gscspace.h */
337
89.2k
        pio->core->gs_next_id = 5; /* Cloned contexts share the state */
338
        /* Set scanconverter to 1 (default) */
339
89.2k
        pio->core->scanconverter = GS_SCANCONVERTER_DEFAULT;
340
        /* Initialise the underlying CMS. */
341
89.2k
        pio->core->cms_context = gscms_create(mem);
342
89.2k
        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
89.2k
    }
354
355
    /* Now set the non zero/false/NULL things */
356
89.2k
    pio->memory               = mem;
357
358
    /* Need to set this before calling gs_lib_ctx_set_icc_directory. */
359
89.2k
    mem->gs_lib_ctx = pio;
360
    /* Initialize our default ICCProfilesDir */
361
89.2k
    pio->profiledir = NULL;
362
89.2k
    pio->profiledir_len = 0;
363
89.2k
    pio->icc_color_accuracy = MAX_COLOR_ACCURACY;
364
89.2k
    if (gs_lib_ctx_set_icc_directory(mem, DEFAULT_DIR_ICC, strlen(DEFAULT_DIR_ICC)) < 0)
365
0
      goto Failure;
366
367
89.2k
    if (gs_lib_ctx_set_default_device_list(mem, gs_dev_defaults,
368
89.2k
                                           strlen(gs_dev_defaults)) < 0)
369
0
        goto Failure;
370
371
    /* Initialise any lock required for the jpx codec */
372
89.2k
    if (sjpxd_create(mem))
373
0
        goto Failure;
374
375
89.2k
    pio->client_check_file_permission = NULL;
376
89.2k
    gp_get_realtime(pio->real_time_0);
377
378
89.2k
    if (gs_lib_ctx_alloc_root_structure(mem, &pio->name_table_root))
379
0
        goto Failure;
380
381
89.2k
    if (gs_lib_ctx_alloc_root_structure(mem, &pio->io_device_table_root))
382
0
        goto Failure;
383
384
89.2k
    if (gs_lib_ctx_alloc_root_structure(mem, &pio->font_dir_root))
385
0
        goto Failure;
386
89.2k
    if (gs_add_control_path(mem, gs_permit_file_writing, gp_null_file_name) < 0)
387
0
        goto Failure;
388
389
89.2k
    return 0;
390
391
0
Failure:
392
0
    gs_lib_ctx_fin(mem);
393
0
    return -1;
394
89.2k
}
395
396
static void remove_ctx_pointers(gs_memory_t *mem)
397
89.2k
{
398
89.2k
    mem->gs_lib_ctx = NULL;
399
89.2k
    if (mem->stable_memory && mem->stable_memory != mem)
400
0
        remove_ctx_pointers(mem->stable_memory);
401
89.2k
    if (mem->non_gc_memory && mem->non_gc_memory != mem)
402
0
        remove_ctx_pointers(mem->non_gc_memory);
403
89.2k
    if (mem->thread_safe_memory && mem->thread_safe_memory != mem)
404
0
        remove_ctx_pointers(mem->thread_safe_memory);
405
89.2k
}
406
407
void gs_lib_ctx_fin(gs_memory_t *mem)
408
89.2k
{
409
89.2k
    gs_lib_ctx_t *ctx;
410
89.2k
    gs_memory_t *ctx_mem;
411
89.2k
    int refs, i;
412
89.2k
    gs_fs_list_t *fs;
413
89.2k
    gs_callout_list_t *entry;
414
415
89.2k
    if (!mem || !mem->gs_lib_ctx)
416
0
        return;
417
418
89.2k
    ctx = mem->gs_lib_ctx;
419
89.2k
    ctx_mem = ctx->memory;
420
421
89.2k
    sjpxd_destroy(mem);
422
89.2k
    gs_free_object(ctx_mem, ctx->profiledir,
423
89.2k
        "gs_lib_ctx_fin");
424
425
89.2k
    gs_free_object(ctx_mem, ctx->default_device_list,
426
89.2k
                "gs_lib_ctx_fin");
427
428
89.2k
    gs_free_object(ctx_mem, ctx->name_table_root, "gs_lib_ctx_fin");
429
89.2k
    gs_free_object(ctx_mem, ctx->io_device_table_root, "gs_lib_ctx_fin");
430
89.2k
    gs_free_object(ctx_mem, ctx->font_dir_root, "gs_lib_ctx_fin");
431
432
89.2k
    gx_monitor_enter((gx_monitor_t *)(ctx->core->monitor));
433
89.2k
    refs = --ctx->core->refs;
434
89.2k
    gx_monitor_leave((gx_monitor_t *)(ctx->core->monitor));
435
89.2k
    if (refs == 0) {
436
89.2k
        gscms_destroy(ctx->core->cms_context);
437
89.2k
        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
89.2k
        gs_purge_scratch_files(ctx->core->memory);
442
89.2k
        gs_purge_control_paths(ctx->core->memory, gs_permit_file_reading);
443
89.2k
        gs_purge_control_paths(ctx->core->memory, gs_permit_file_writing);
444
89.2k
        gs_purge_control_paths(ctx->core->memory, gs_permit_file_control);
445
446
89.2k
        fs = ctx->core->fs;
447
178k
        while (fs) {
448
89.2k
            gs_fs_list_t *next = fs->next;
449
89.2k
            gs_free_object(fs->memory, fs, "gs_lib_ctx_fin");
450
89.2k
            fs = next;
451
89.2k
        }
452
453
89.2k
        entry = ctx->core->callouts;
454
89.2k
        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
1.69M
        for (i = 0; i < ctx->core->argc; i++)
461
1.60M
            gs_free_object(ctx->core->memory, ctx->core->argv[i], "gs_lib_ctx_arg");
462
89.2k
        gs_free_object(ctx->core->memory, ctx->core->argv, "gs_lib_ctx_args");
463
464
89.2k
        gs_free_object(ctx->core->memory, ctx->core, "gs_lib_ctx_fin");
465
89.2k
    }
466
89.2k
    remove_ctx_pointers(ctx_mem);
467
468
89.2k
    gs_free_object(ctx_mem, ctx, "gs_lib_ctx_init");
469
89.2k
}
470
471
gs_lib_ctx_t *gs_lib_ctx_get_interp_instance(const gs_memory_t *mem)
472
424M
{
473
424M
    if (mem == NULL)
474
0
        return NULL;
475
424M
    return mem->gs_lib_ctx;
476
424M
}
477
478
void *gs_lib_ctx_get_cms_context( const gs_memory_t *mem )
479
62.0M
{
480
62.0M
    if (mem == NULL)
481
0
        return NULL;
482
62.0M
    return mem->gs_lib_ctx->core->cms_context;
483
62.0M
}
484
485
int gs_lib_ctx_get_act_on_uel( const gs_memory_t *mem )
486
89.2k
{
487
89.2k
    if (mem == NULL)
488
0
        return 0;
489
89.2k
    return mem->gs_lib_ctx->core->act_on_uel;
490
89.2k
}
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
2.84M
{
497
2.84M
    int code;
498
2.84M
    gs_lib_ctx_t *pio = mem->gs_lib_ctx;
499
2.84M
    gs_lib_ctx_core_t *core = pio->core;
500
501
2.84M
    if (len == 0)
502
0
        return 0;
503
2.84M
    if (core->stdout_is_redirected) {
504
2.84M
        if (core->stdout_to_stderr)
505
0
            return errwrite(mem, str, len);
506
2.84M
        code = gp_fwrite(str, 1, len, core->fstdout2);
507
2.84M
        gp_fflush(core->fstdout2);
508
2.84M
    } 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
2.84M
    return code;
515
2.84M
}
516
517
int errwrite(const gs_memory_t *mem, const char *str, int len)
518
326k
{
519
326k
    int code;
520
326k
    gs_lib_ctx_t *ctx;
521
326k
    gs_lib_ctx_core_t *core;
522
326k
    if (len == 0)
523
0
        return 0;
524
326k
    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
326k
    ctx = mem->gs_lib_ctx;
532
326k
    if (ctx == NULL)
533
0
      return 0;
534
326k
    core = ctx->core;
535
326k
    if (core->stderr_fn)
536
326k
        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
326k
}
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
6.13M
{
568
6.13M
    int code = 0;
569
6.13M
    if (mem->gs_lib_ctx->client_check_file_permission != NULL) {
570
6.13M
        code = mem->gs_lib_ctx->client_check_file_permission(mem, fname, len, permission);
571
6.13M
    }
572
6.13M
    return code;
573
6.13M
}
574
575
static void
576
rewrite_percent_specifiers(char *s)
577
91.0k
{
578
91.0k
    char *match_start;
579
580
91.0k
    while (*s)
581
91.0k
    {
582
91.0k
        int flags;
583
        /* Find a % */
584
954k
        while (*s && *s != '%')
585
863k
            s++;
586
91.0k
        if (*s == 0)
587
91.0k
            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
91.0k
}
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
90.1k
{
653
90.1k
    char f[gp_file_name_sizeof];
654
90.1k
    int code;
655
656
    /* Be sure the string copy will fit */
657
90.1k
    if (strlen(fname) >= gp_file_name_sizeof)
658
0
        return gs_error_rangecheck;
659
90.1k
    strcpy(f, fname);
660
    /* Try to rewrite any %d (or similar) in the string */
661
90.1k
    rewrite_percent_specifiers(f);
662
663
90.1k
    code = gs_add_control_path(mem, gs_permit_file_control, f);
664
90.1k
    if (code < 0)
665
0
        return code;
666
90.1k
    return gs_add_control_path(mem, gs_permit_file_writing, f);
667
90.1k
}
668
669
int
670
gs_remove_outputfile_control_path(gs_memory_t *mem, const char *fname)
671
914
{
672
914
    char f[gp_file_name_sizeof];
673
914
    int code;
674
675
    /* Be sure the string copy will fit */
676
914
    if (strlen(fname) >= gp_file_name_sizeof)
677
0
        return gs_error_rangecheck;
678
914
    strcpy(f, fname);
679
    /* Try to rewrite any %d (or similar) in the string */
680
914
    rewrite_percent_specifiers(f);
681
682
914
    code = gs_remove_control_path(mem, gs_permit_file_control, f);
683
914
    if (code < 0)
684
0
        return code;
685
914
    return gs_remove_control_path(mem, gs_permit_file_writing, f);
686
914
}
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
11.2M
{
710
11.2M
    return gs_add_control_path_len_flags(mem, type, path, len, 0);
711
11.2M
}
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
11.8M
{
716
11.8M
    gs_path_control_set_t *control;
717
11.8M
    unsigned int n, i;
718
11.8M
    gs_lib_ctx_core_t *core;
719
11.8M
    char *buffer;
720
11.8M
    uint rlen;
721
722
11.8M
    if (path == NULL || len == 0)
723
0
        return 0;
724
725
11.8M
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
726
11.8M
        (core = mem->gs_lib_ctx->core) == NULL)
727
0
        return gs_error_unknownerror;
728
729
11.8M
    switch(type) {
730
10.9M
        case gs_permit_file_reading:
731
10.9M
            control = &core->permit_reading;
732
10.9M
            break;
733
462k
        case gs_permit_file_writing:
734
462k
            control = &core->permit_writing;
735
462k
            break;
736
373k
        case gs_permit_file_control:
737
373k
            control = &core->permit_control;
738
373k
            break;
739
0
        default:
740
0
            return gs_error_rangecheck;
741
11.8M
    }
742
743
11.8M
    rlen = len+1;
744
11.8M
    buffer = (char *)gs_alloc_bytes(core->memory, rlen, "gp_validate_path");
745
11.8M
    if (buffer == NULL)
746
0
        return gs_error_VMerror;
747
748
11.8M
    if (gp_file_name_reduce(path, (uint)len, buffer, &rlen) != gp_combine_success)
749
0
        return gs_error_invalidfileaccess;
750
11.8M
    buffer[rlen] = 0;
751
752
11.8M
    n = control->num;
753
106M
    for (i = 0; i < n; i++)
754
103M
    {
755
103M
        if (strncmp(control->entry[i].path, buffer, rlen) == 0 &&
756
103M
            control->entry[i].path[rlen] == 0) {
757
8.20M
            gs_free_object(core->memory, buffer, "gs_add_control_path_len");
758
8.20M
            return 0; /* Already there! */
759
8.20M
        }
760
103M
    }
761
762
3.61M
    if (control->num == control->max) {
763
584k
        gs_path_control_entry_t *p;
764
765
584k
        n = control->max * 2;
766
584k
        if (n == 0) {
767
267k
            n = 4;
768
267k
            p = (gs_path_control_entry_t *)gs_alloc_bytes(core->memory, sizeof(*p)*n, "gs_lib_ctx(entries)");
769
267k
        } else
770
316k
            p = (gs_path_control_entry_t *)gs_resize_object(core->memory, control->entry, sizeof(*p)*n, "gs_lib_ctx(entries)");
771
584k
        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
584k
        control->entry = p;
776
584k
        control->max = n;
777
584k
    }
778
779
3.61M
    n = control->num;
780
3.61M
    control->entry[n].path = buffer;
781
3.61M
    control->entry[n].path[len] = 0;
782
3.61M
    control->entry[n].flags = flags;
783
3.61M
    control->num++;
784
785
3.61M
    return 0;
786
3.61M
}
787
788
int
789
gs_add_control_path(const gs_memory_t *mem, gs_path_control_t type, const char *path)
790
269k
{
791
269k
    return gs_add_control_path_len_flags(mem, type, path, path ? strlen(path) : 0, 0);
792
269k
}
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
315k
{
797
315k
    return gs_add_control_path_len_flags(mem, type, path, path ? strlen(path) : 0, flags);
798
315k
}
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
1.82k
{
809
1.82k
    gs_path_control_set_t *control;
810
1.82k
    unsigned int n, i;
811
1.82k
    gs_lib_ctx_core_t *core;
812
1.82k
    char *buffer;
813
1.82k
    uint rlen;
814
815
1.82k
    if (path == NULL || len == 0)
816
0
        return 0;
817
818
1.82k
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
819
1.82k
        (core = mem->gs_lib_ctx->core) == NULL)
820
0
        return gs_error_unknownerror;
821
822
1.82k
    switch(type) {
823
0
        case gs_permit_file_reading:
824
0
            control = &core->permit_reading;
825
0
            break;
826
914
        case gs_permit_file_writing:
827
914
            control = &core->permit_writing;
828
914
            break;
829
914
        case gs_permit_file_control:
830
914
            control = &core->permit_control;
831
914
            break;
832
0
        default:
833
0
            return gs_error_rangecheck;
834
1.82k
    }
835
836
1.82k
    rlen = len+1;
837
1.82k
    buffer = (char *)gs_alloc_bytes(core->memory, rlen, "gp_validate_path");
838
1.82k
    if (buffer == NULL)
839
0
        return gs_error_VMerror;
840
841
1.82k
    if (gp_file_name_reduce(path, (uint)len, buffer, &rlen) != gp_combine_success)
842
0
        return gs_error_invalidfileaccess;
843
1.82k
    buffer[rlen] = 0;
844
845
1.82k
    n = control->num;
846
10.0k
    for (i = 0; i < n; i++) {
847
10.0k
        if (control->entry[i].flags == flags &&
848
10.0k
            strncmp(control->entry[i].path, buffer, len) == 0 &&
849
10.0k
            control->entry[i].path[len] == 0)
850
1.82k
            break;
851
10.0k
    }
852
1.82k
    gs_free_object(core->memory, buffer, "gs_remove_control_path_len");
853
1.82k
    if (i == n)
854
0
        return 0;
855
856
1.82k
    gs_free_object(core->memory, control->entry[i].path, "gs_lib_ctx(path)");
857
4.60k
    for (;i < n-1; i++)
858
2.77k
        control->entry[i] = control->entry[i+1];
859
1.82k
    control->num = n-1;
860
861
1.82k
    return 0;
862
1.82k
}
863
864
int
865
gs_remove_control_path(const gs_memory_t *mem, gs_path_control_t type, const char *path)
866
1.82k
{
867
1.82k
    if (path == NULL)
868
0
        return 0;
869
870
1.82k
    return gs_remove_control_path_len_flags(mem, type, path, strlen(path), 0);
871
1.82k
}
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
267k
{
885
267k
    gs_path_control_set_t *control;
886
267k
    unsigned int n, in, out;
887
267k
    gs_lib_ctx_core_t *core;
888
889
267k
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
890
267k
        (core = mem->gs_lib_ctx->core) == NULL)
891
0
        return;
892
893
267k
    switch(type) {
894
89.2k
        case gs_permit_file_reading:
895
89.2k
            control = &core->permit_reading;
896
89.2k
            break;
897
89.2k
        case gs_permit_file_writing:
898
89.2k
            control = &core->permit_writing;
899
89.2k
            break;
900
89.2k
        case gs_permit_file_control:
901
89.2k
            control = &core->permit_control;
902
89.2k
            break;
903
0
        default:
904
0
            return;
905
267k
    }
906
907
267k
    n = control->num;
908
3.56M
    for (in = out = 0; in < n; in++) {
909
3.30M
        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
3.30M
            gs_free_object(core->memory, control->entry[in].path, "gs_lib_ctx(path)");
914
3.30M
    }
915
267k
    control->num = out;
916
267k
    if (out == 0) {
917
267k
        gs_free_object(core->memory, control->entry, "gs_lib_ctx(paths)");
918
267k
        control->entry = NULL;
919
267k
        control->max = 0;
920
267k
    }
921
267k
}
922
923
void
924
gs_purge_scratch_files(const gs_memory_t *mem)
925
89.2k
{
926
89.2k
    gs_path_control_set_t *control;
927
89.2k
    gs_path_control_t type;
928
89.2k
    int n, in, out;
929
89.2k
    gs_lib_ctx_core_t *core;
930
931
89.2k
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
932
89.2k
        (core = mem->gs_lib_ctx->core) == NULL)
933
0
        return;
934
935
357k
    for (type = gs_permit_file_reading; type <= gs_permit_file_control; type++)
936
267k
    {
937
267k
        switch(type) {
938
0
            default:
939
89.2k
            case gs_permit_file_reading:
940
89.2k
                control = &core->permit_reading;
941
89.2k
                break;
942
89.2k
            case gs_permit_file_writing:
943
89.2k
                control = &core->permit_writing;
944
89.2k
                break;
945
89.2k
            case gs_permit_file_control:
946
89.2k
                control = &core->permit_control;
947
89.2k
                break;
948
267k
        }
949
950
267k
        n = control->num;
951
3.88M
        for (in = out = 0; in < n; in++) {
952
3.61M
            if ((control->entry[in].flags & gs_path_control_flag_is_scratch_file) == 0) {
953
                /* Only purge scratch files! */
954
3.30M
                control->entry[out++] = control->entry[in];
955
3.30M
            } else {
956
315k
                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
105k
                    gp_unlink_impl(core->memory, control->entry[in].path);
961
105k
                }
962
315k
                gs_free_object(core->memory, control->entry[in].path, "gs_lib_ctx(path)");
963
315k
            }
964
3.61M
        }
965
267k
        control->num = out;
966
267k
        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
267k
    }
972
89.2k
}
973
974
void
975
gs_activate_path_control(gs_memory_t *mem, int enable)
976
89.2k
{
977
89.2k
    gs_lib_ctx_core_t *core;
978
979
89.2k
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
980
89.2k
        (core = mem->gs_lib_ctx->core) == NULL)
981
0
        return;
982
983
89.2k
    core->path_control_active = enable;
984
89.2k
}
985
986
int
987
gs_is_path_control_active(const gs_memory_t *mem)
988
2.05M
{
989
2.05M
    gs_lib_ctx_core_t *core;
990
991
2.05M
    if (mem == NULL || mem->gs_lib_ctx == NULL ||
992
2.05M
        (core = mem->gs_lib_ctx->core) == NULL)
993
0
        return 0;
994
995
2.05M
    return core->path_control_active;
996
2.05M
}
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
1.51M
{
1055
1.51M
    gs_lib_ctx_core_t *core;
1056
1.51M
    size_t len;
1057
1.51M
    const char *p;
1058
1.51M
    int elide = 0;
1059
1060
1.51M
    if (ctx == NULL || ctx->core == NULL || arg == NULL)
1061
0
        return 0;
1062
1063
    /* Sanitize arg */
1064
1.51M
    switch(*arg)
1065
1.51M
    {
1066
1.51M
    case '-':
1067
1.51M
        switch (arg[1])
1068
1.51M
        {
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
892k
        case 'd': /* We can let -dFoo=<whatever> through unchanged */
1094
892k
        case 'D': /* We can let -DFoo=<whatever> through unchanged */
1095
981k
        case 'r': /* We can let -r through unchanged */
1096
981k
        case 'Z': /* We can let -Z through unchanged */
1097
981k
        case 'g': /* We can let -g through unchanged */
1098
981k
        case 'P': /* We can let -P through unchanged */
1099
981k
        case '+': /* We can let -+ through unchanged */
1100
1.07M
        case '_': /* We can let -_ through unchanged */
1101
1.07M
        case 'u': /* We can let -u through unchanged */
1102
1.07M
        case 'q': /* We can let -q through unchanged */
1103
1.07M
            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
357k
        case 's':
1114
357k
        case 'S':
1115
            /* By default, we want to keep the key, but lose the value */
1116
357k
            p = arg+2;
1117
3.65M
            while (*p && *p != '=')
1118
3.30M
                p++;
1119
357k
            if (*p == '=')
1120
357k
                p++;
1121
357k
            if (*p == 0)
1122
0
                break; /* No value to elide */
1123
            /* Check for our whitelisted values here */
1124
357k
#define ARG_MATCHES(STR, ARG, LEN) \
1125
2.32M
    (strlen(STR) == LEN && !memcmp(STR, ARG, LEN))
1126
357k
            if (ARG_MATCHES("DEFAULTPAPERSIZE", arg+2, p-arg-3))
1127
0
                break;
1128
357k
            if (ARG_MATCHES("DEVICE", arg+2, p-arg-3))
1129
89.2k
                break;
1130
267k
            if (ARG_MATCHES("PAPERSIZE", arg+2, p-arg-3))
1131
0
                break;
1132
267k
            if (ARG_MATCHES("SUBSTFONT", arg+2, p-arg-3))
1133
0
                break;
1134
267k
            if (ARG_MATCHES("ColorConversionStrategy", arg+2, p-arg-3))
1135
0
                break;
1136
267k
            if (ARG_MATCHES("NupControl", arg+2, p-arg-3))
1137
0
                break;
1138
267k
            if (ARG_MATCHES("PageList", arg+2, p-arg-3))
1139
0
                break;
1140
267k
            if (ARG_MATCHES("ProcessColorModel", arg+2, p-arg-3))
1141
0
                break;
1142
267k
#undef ARG_MATCHES
1143
            /* Didn't match a whitelisted value, so elide it. */
1144
267k
            elide = 1;
1145
267k
            break;
1146
89.2k
        default:
1147
            /* Shouldn't happen, but elide it just in case */
1148
89.2k
            arg = "?";
1149
89.2k
            break;
1150
1.51M
        }
1151
1.51M
        break;
1152
1.51M
    case '@':
1153
        /* Shouldn't happen */
1154
0
    default:
1155
        /* Anything else should be elided */
1156
0
        arg = "?";
1157
0
        break;
1158
1.51M
    }
1159
1160
1.51M
    core = ctx->core;
1161
1.51M
    if (elide)
1162
267k
        len = p-arg;
1163
1.24M
    else
1164
1.24M
        len = strlen(arg);
1165
1166
1.51M
    if (core->arg_max == core->argc) {
1167
267k
        char **argv;
1168
267k
        int newlen = core->arg_max * 2;
1169
267k
        if (newlen == 0)
1170
0
            newlen = 4;
1171
267k
        argv = (char **)gs_alloc_bytes(ctx->core->memory, sizeof(char *) * newlen,
1172
267k
                                       "gs_lib_ctx_args");
1173
267k
        if (argv == NULL)
1174
0
            return gs_error_VMerror;
1175
267k
        if (core->argc > 0) {
1176
267k
            memcpy(argv, core->argv, sizeof(char *) * core->argc);
1177
267k
            gs_free_object(ctx->memory, core->argv, "gs_lib_ctx_args");
1178
267k
        }
1179
267k
        core->argv = argv;
1180
267k
        core->arg_max = newlen;
1181
267k
    }
1182
1183
1.51M
    core->argv[core->argc] = (char *)gs_alloc_bytes(ctx->core->memory, len+1+elide,
1184
1.51M
                                                    "gs_lib_ctx_arg");
1185
1.51M
    if (core->argv[core->argc] == NULL)
1186
0
        return gs_error_VMerror;
1187
1.51M
    memcpy(core->argv[core->argc], arg, len);
1188
1.51M
    if (elide) {
1189
267k
        core->argv[core->argc][len] = '?';
1190
267k
    }
1191
1.51M
    core->argv[core->argc][len+elide] = 0;
1192
1.51M
    core->argc++;
1193
1194
1.51M
    return 0;
1195
1.51M
}
1196
1197
int
1198
gs_lib_ctx_stash_exe(gs_lib_ctx_t *ctx, const char *arg)
1199
89.2k
{
1200
89.2k
    gs_lib_ctx_core_t *core;
1201
89.2k
    size_t len;
1202
89.2k
    const char *p, *word;
1203
89.2k
    const char *sep = gp_file_name_directory_separator();
1204
89.2k
    size_t seplen = strlen(sep);
1205
1206
89.2k
    if (ctx == NULL || ctx->core == NULL || arg == NULL)
1207
0
        return 0;
1208
1209
    /* Sanitize arg */
1210
89.2k
    p = arg;
1211
89.2k
    word = NULL;
1212
267k
    for (p = arg; *p; p++) {
1213
178k
        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
178k
    }
1222
89.2k
    len = p - (word ? word : arg) + 1;
1223
89.2k
    if (word)
1224
0
        len += 5;
1225
1226
89.2k
    core = ctx->core;
1227
89.2k
    if (core->arg_max == core->argc) {
1228
89.2k
        char **argv;
1229
89.2k
        int newlen = core->arg_max * 2;
1230
89.2k
        if (newlen == 0)
1231
89.2k
            newlen = 4;
1232
89.2k
        argv = (char **)gs_alloc_bytes(ctx->core->memory, sizeof(char *) * newlen,
1233
89.2k
                                       "gs_lib_ctx_args");
1234
89.2k
        if (argv == NULL)
1235
0
            return gs_error_VMerror;
1236
89.2k
        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
89.2k
        core->argv = argv;
1241
89.2k
        core->arg_max = newlen;
1242
89.2k
    }
1243
1244
89.2k
    core->argv[core->argc] = (char *)gs_alloc_bytes(ctx->core->memory, len,
1245
89.2k
                                                    "gs_lib_ctx_arg");
1246
89.2k
    if (core->argv[core->argc] == NULL)
1247
0
        return gs_error_VMerror;
1248
89.2k
    if (word)
1249
0
        strcpy(core->argv[core->argc], "path/");
1250
89.2k
    else
1251
89.2k
        core->argv[core->argc][0] = 0;
1252
89.2k
    strcat(core->argv[core->argc], word ? word : arg);
1253
89.2k
    core->argc++;
1254
1255
89.2k
    return 0;
1256
89.2k
}
1257
1258
int gs_lib_ctx_get_args(gs_lib_ctx_t *ctx, const char * const **argv)
1259
16.0k
{
1260
16.0k
    gs_lib_ctx_core_t *core;
1261
1262
16.0k
    if (ctx == NULL || ctx->core == NULL || argv == NULL)
1263
0
        return 0;
1264
1265
16.0k
    core = ctx->core;
1266
16.0k
    *argv = (const char * const *)core->argv;
1267
16.0k
    return core->argc;
1268
16.0k
}
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
17
{
1371
17
    memset(globals, 0, sizeof(*globals));
1372
17
}