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