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