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