/src/ghostpdl/psi/icontext.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 | | /* Context state operations */ |
18 | | #include "ghost.h" |
19 | | #include "gsstruct.h" /* for gxalloc.h */ |
20 | | #include "gxalloc.h" |
21 | | #include "ierrors.h" |
22 | | #include "stream.h" /* for files.h */ |
23 | | #include "files.h" |
24 | | #include "idict.h" |
25 | | #include "igstate.h" |
26 | | #include "icontext.h" |
27 | | #include "interp.h" |
28 | | #include "isave.h" |
29 | | #include "dstack.h" |
30 | | #include "estack.h" |
31 | | #include "store.h" |
32 | | |
33 | | /* Declare the GC descriptors for embedded objects. */ |
34 | | extern_st(st_gs_dual_memory); |
35 | | extern_st(st_ref_stack); |
36 | | extern_st(st_dict_stack); |
37 | | extern_st(st_exec_stack); |
38 | | extern_st(st_op_stack); |
39 | | |
40 | | /* GC descriptors */ |
41 | | static |
42 | | CLEAR_MARKS_PROC(context_state_clear_marks) |
43 | 303k | { |
44 | 303k | gs_context_state_t *const pcst = vptr; |
45 | | |
46 | 303k | r_clear_attrs(&pcst->stdio[0], l_mark); |
47 | 303k | r_clear_attrs(&pcst->stdio[1], l_mark); |
48 | 303k | r_clear_attrs(&pcst->stdio[2], l_mark); |
49 | 303k | r_clear_attrs(&pcst->error_object, l_mark); |
50 | 303k | r_clear_attrs(&pcst->userparams, l_mark); |
51 | 303k | r_clear_attrs(&pcst->internaldict, l_mark); |
52 | 303k | r_clear_attrs(&pcst->op_array_table_global.table, l_mark); |
53 | 303k | r_clear_attrs(&pcst->op_array_table_local.table, l_mark); |
54 | 303k | } |
55 | | static |
56 | 11.5M | ENUM_PTRS_WITH(context_state_enum_ptrs, gs_context_state_t *pcst) { |
57 | 4.24M | index -= 12; |
58 | 4.24M | if (index < st_gs_dual_memory_num_ptrs) |
59 | 0 | return ENUM_USING(st_gs_dual_memory, &pcst->memory, |
60 | 4.24M | sizeof(pcst->memory), index); |
61 | 4.24M | index -= st_gs_dual_memory_num_ptrs; |
62 | 4.24M | if (index < st_dict_stack_num_ptrs) |
63 | 1.21M | return ENUM_USING(st_dict_stack, &pcst->dict_stack, |
64 | 4.24M | sizeof(pcst->dict_stack), index); |
65 | 3.03M | index -= st_dict_stack_num_ptrs; |
66 | 3.03M | if (index < st_exec_stack_num_ptrs) |
67 | 1.21M | return ENUM_USING(st_exec_stack, &pcst->exec_stack, |
68 | 3.03M | sizeof(pcst->exec_stack), index); |
69 | 1.81M | index -= st_exec_stack_num_ptrs; |
70 | 1.81M | return ENUM_USING(st_op_stack, &pcst->op_stack, |
71 | 3.03M | sizeof(pcst->op_stack), index); |
72 | 3.03M | } |
73 | 3.03M | ENUM_PTR(0, gs_context_state_t, pgs); |
74 | 606k | case 1: ENUM_RETURN_REF(&pcst->stdio[0]); |
75 | 606k | case 2: ENUM_RETURN_REF(&pcst->stdio[1]); |
76 | 606k | case 3: ENUM_RETURN_REF(&pcst->stdio[2]); |
77 | 606k | case 4: ENUM_RETURN_REF(&pcst->error_object); |
78 | 3.03M | ENUM_PTR(5, gs_context_state_t, invalid_file_stream); |
79 | 606k | case 6: ENUM_RETURN_REF(&pcst->userparams); |
80 | 606k | case 7: ENUM_RETURN_REF(&pcst->internaldict); |
81 | 3.03M | ENUM_PTR(8, gs_context_state_t, op_array_table_global.nx_table); |
82 | 3.03M | ENUM_PTR(9, gs_context_state_t, op_array_table_local.nx_table); |
83 | 606k | case 10: ENUM_RETURN_REF(&pcst->op_array_table_global.table); |
84 | 606k | case 11: ENUM_RETURN_REF(&pcst->op_array_table_local.table); |
85 | 11.5M | ENUM_PTRS_END |
86 | 303k | static RELOC_PTRS_WITH(context_state_reloc_ptrs, gs_context_state_t *pcst); |
87 | 303k | RELOC_PTR(gs_context_state_t, pgs); |
88 | 303k | RELOC_USING(st_gs_dual_memory, &pcst->memory, sizeof(pcst->memory)); |
89 | | /******* WHY DON'T WE CLEAR THE l_mark OF stdio? ******/ |
90 | 303k | RELOC_REF_VAR(pcst->stdio[0]); |
91 | 303k | RELOC_REF_VAR(pcst->stdio[1]); |
92 | 303k | RELOC_REF_VAR(pcst->stdio[2]); |
93 | 303k | RELOC_PTR(gs_context_state_t, invalid_file_stream); |
94 | 303k | RELOC_REF_VAR(pcst->error_object); |
95 | 303k | r_clear_attrs(&pcst->error_object, l_mark); |
96 | 303k | RELOC_REF_VAR(pcst->userparams); |
97 | 303k | r_clear_attrs(&pcst->userparams, l_mark); |
98 | 303k | RELOC_REF_VAR(pcst->internaldict); |
99 | 303k | r_clear_attrs(&pcst->internaldict, l_mark); |
100 | 303k | RELOC_PTR(gs_context_state_t, op_array_table_global.nx_table); |
101 | 303k | RELOC_PTR(gs_context_state_t, op_array_table_local.nx_table); |
102 | 303k | RELOC_REF_VAR(pcst->op_array_table_global.table); |
103 | 303k | r_clear_attrs(&pcst->op_array_table_global.table, l_mark); |
104 | 303k | RELOC_REF_VAR(pcst->op_array_table_local.table); |
105 | 303k | r_clear_attrs(&pcst->op_array_table_local.table, l_mark); |
106 | 303k | RELOC_USING(st_dict_stack, &pcst->dict_stack, sizeof(pcst->dict_stack)); |
107 | 303k | RELOC_USING(st_exec_stack, &pcst->exec_stack, sizeof(pcst->exec_stack)); |
108 | 303k | RELOC_USING(st_op_stack, &pcst->op_stack, sizeof(pcst->op_stack)); |
109 | 303k | RELOC_PTRS_END |
110 | | public_st_context_state(); |
111 | | |
112 | | /* Allocate the state of a context. */ |
113 | | int |
114 | | context_state_alloc(gs_context_state_t ** ppcst, |
115 | | const ref *psystem_dict, |
116 | | const gs_dual_memory_t * dmem) |
117 | 147k | { |
118 | 147k | gs_ref_memory_t *mem = dmem->space_local; |
119 | 147k | gs_context_state_t *pcst = *ppcst; |
120 | 147k | int code; |
121 | 147k | int i; |
122 | | |
123 | 147k | if (pcst == 0) { |
124 | 147k | pcst = gs_alloc_struct((gs_memory_t *) mem, gs_context_state_t, |
125 | 147k | &st_context_state, "context_state_alloc"); |
126 | 147k | if (pcst == 0) |
127 | 0 | return_error(gs_error_VMerror); |
128 | 147k | } |
129 | | /* Make sure pcst->memory is valid, in case we return an error. */ |
130 | 147k | pcst->memory = *dmem; |
131 | 147k | code = gs_interp_alloc_stacks(mem, pcst); |
132 | 147k | if (code < 0) |
133 | 0 | goto x0; |
134 | | /* |
135 | | * We have to initialize the dictionary stack early, |
136 | | * for far-off references to systemdict. |
137 | | */ |
138 | 147k | pcst->dict_stack.system_dict = *psystem_dict; |
139 | 147k | pcst->dict_stack.min_size = 0; |
140 | 147k | pcst->dict_stack.userdict_index = 0; |
141 | 147k | pcst->pgs = int_gstate_alloc(dmem); |
142 | 147k | if (pcst->pgs == 0) { |
143 | 0 | code = gs_note_error(gs_error_VMerror); |
144 | 0 | goto x1; |
145 | 0 | } |
146 | 147k | pcst->language_level = 1; |
147 | 147k | make_false(&pcst->array_packing); |
148 | 147k | make_int(&pcst->binary_object_format, 0); |
149 | 147k | pcst->nv_page_count = 0; |
150 | 147k | pcst->rand_state = rand_state_initial; |
151 | 147k | pcst->usertime_inited = false; |
152 | 147k | pcst->plugin_list = 0; |
153 | 147k | make_t(&pcst->error_object, t__invalid); |
154 | 147k | { /* |
155 | | * Create an empty userparams dictionary of the right size. |
156 | | * If we can't determine the size, pick an arbitrary one. |
157 | | */ |
158 | 147k | ref *puserparams; |
159 | 147k | uint size; |
160 | 147k | ref *system_dict = &pcst->dict_stack.system_dict; |
161 | | |
162 | 147k | if (dict_find_string(system_dict, "userparams", &puserparams) > 0) |
163 | 0 | size = dict_length(puserparams); |
164 | 147k | else |
165 | 147k | size = 300; |
166 | 147k | code = dict_alloc(pcst->memory.space_local, size, &pcst->userparams); |
167 | 147k | if (code < 0) |
168 | 0 | goto x2; |
169 | | /* PostScript code initializes the user parameters. */ |
170 | 147k | } |
171 | 147k | { /* |
172 | | * Create an empty internaldict dictionary. |
173 | | */ |
174 | 147k | ref *internaldict; |
175 | | |
176 | 147k | code = dict_alloc(pcst->memory.space_local, 13, &pcst->internaldict); |
177 | 147k | if (code < 0) |
178 | 0 | goto x2; |
179 | | /* PostScript code initializes the user parameters. */ |
180 | 147k | } |
181 | 147k | pcst->scanner_options = 0; |
182 | 147k | pcst->LockFilePermissions = false; |
183 | 147k | pcst->starting_arg_file = false; |
184 | 147k | pcst->RenderTTNotdef = true; |
185 | | |
186 | 147k | pcst->invalid_file_stream = (stream*)gs_alloc_struct_immovable(mem->stable_memory, |
187 | 147k | stream, &st_stream, |
188 | 147k | "context_state_alloc"); |
189 | 147k | if (pcst->invalid_file_stream == NULL) { |
190 | 0 | code = gs_note_error(gs_error_VMerror); |
191 | 0 | goto x3; |
192 | 0 | } |
193 | | |
194 | 147k | s_init(pcst->invalid_file_stream, mem->stable_memory); |
195 | 147k | sread_string(pcst->invalid_file_stream, NULL, 0); |
196 | 147k | s_init_no_id(pcst->invalid_file_stream); |
197 | | |
198 | | /* The initial stdio values are bogus.... */ |
199 | 147k | make_file(&pcst->stdio[0], a_readonly | avm_invalid_file_entry, 1, |
200 | 147k | pcst->invalid_file_stream); |
201 | 147k | make_file(&pcst->stdio[1], a_all | avm_invalid_file_entry, 1, |
202 | 147k | pcst->invalid_file_stream); |
203 | 147k | make_file(&pcst->stdio[2], a_all | avm_invalid_file_entry, 1, |
204 | 147k | pcst->invalid_file_stream); |
205 | 736k | for (i = countof(pcst->memory.spaces_indexed); --i >= 0;) |
206 | 589k | if (dmem->spaces_indexed[i] != 0) |
207 | 441k | ++(dmem->spaces_indexed[i]->num_contexts); |
208 | | /* The number of interpreter "ticks" between calls on the time_slice_proc. |
209 | | * Currently, the clock ticks before each operator, and at each |
210 | | * procedure return. */ |
211 | 147k | pcst->time_slice_ticks = 0x7fff; |
212 | 147k | *ppcst = pcst; |
213 | | |
214 | 147k | pcst->system_params.CurDisplayList = 0; |
215 | 147k | pcst->system_params.CurFormCache = 0; |
216 | 147k | pcst->system_params.CurOutlineCache = 0; |
217 | 147k | pcst->system_params.CurPatternCache = 0; |
218 | 147k | pcst->system_params.CurScreenStorage = 0; |
219 | 147k | pcst->system_params.CurSourceList = 0; |
220 | 147k | pcst->system_params.CurStoredScreenCache = 0; |
221 | 147k | pcst->system_params.CurUPathCache = 0; |
222 | 147k | pcst->system_params.MaxDisplayAndSourceList = 140000; |
223 | 147k | pcst->system_params.MaxDisplayList = 140000; |
224 | 147k | pcst->system_params.MaxFormCache = 100000; |
225 | 147k | pcst->system_params.MaxImageBuffer = 524288; |
226 | 147k | pcst->system_params.MaxOutlineCache = 65000; |
227 | 147k | pcst->system_params.MaxPatternCache = 100000; |
228 | 147k | pcst->system_params.MaxUPathCache = 300000; |
229 | 147k | pcst->system_params.MaxScreenStorage = 84000; |
230 | 147k | pcst->system_params.MaxSourceList = 25000; |
231 | 147k | pcst->system_params.RamSize = 4194304; |
232 | 147k | pcst->system_params.JobTimeout = 0; |
233 | 147k | pcst->system_params.WaitTimeout = 40; |
234 | 147k | pcst->system_params.GenericResourceDir = NULL; |
235 | 147k | pcst->system_params.FontResourceDir = NULL; |
236 | 147k | pcst->system_params.GenericResourcePathSep = NULL; |
237 | 147k | pcst->system_params.PercentDiskFontResourceDir = NULL; |
238 | 147k | pcst->system_params.PercentDiskGenericResourceDir = NULL; |
239 | 147k | pcst->system_params.SystemParamsPassword = NULL; |
240 | 147k | pcst->system_params.StartJobPassword = NULL; |
241 | | |
242 | 147k | pcst->user_params.MaxFormItem = 100000; |
243 | 147k | pcst->user_params.MaxPatternItem = 20000; |
244 | 147k | pcst->user_params.MaxScreenItem = 48000; |
245 | 147k | pcst->user_params.MaxUPathItem = 0; |
246 | 147k | pcst->user_params.MaxSuperScreen = 1016; |
247 | 147k | pcst->user_params.JobName = NULL; |
248 | 147k | pcst->user_params.IdiomRecognition = false; |
249 | 147k | pcst->user_params.HalftoneMode = 0; |
250 | | |
251 | 147k | return 0; |
252 | 0 | x3:/* No need to delete dictionary here, as gc will do it for us. */ |
253 | 0 | x2:gs_gstate_free(pcst->pgs); |
254 | 0 | x1:gs_interp_free_stacks(mem, pcst); |
255 | 0 | x0:if (*ppcst == 0) |
256 | 0 | gs_free_object((gs_memory_t *) mem, pcst, "context_state_alloc"); |
257 | 0 | return code; |
258 | 0 | } |
259 | | |
260 | | /* Load the interpreter state from a context. */ |
261 | | int |
262 | | context_state_load(gs_context_state_t * i_ctx_p) |
263 | 450k | { |
264 | 450k | gs_ref_memory_t *lmem = iimemory_local; |
265 | 450k | ref *system_dict = systemdict; |
266 | 450k | uint space = r_space(system_dict); |
267 | 450k | dict_stack_t *dstack = &idict_stack; |
268 | 450k | int code; |
269 | | |
270 | | /* |
271 | | * Disable save checking, and space check for systemdict, while |
272 | | * copying dictionaries. |
273 | | */ |
274 | 450k | alloc_set_not_in_save(idmemory); |
275 | 450k | r_set_space(system_dict, avm_max); |
276 | | /* |
277 | | * Set systemdict.userparams to the saved copy, and then |
278 | | * set the actual user parameters. Note that we must disable both |
279 | | * space checking and save checking while doing this. Also, |
280 | | * we must do this after copying localdicts (if required), because |
281 | | * userparams also appears in localdicts. |
282 | | */ |
283 | 450k | code = dict_put_string(system_dict, "userparams", &i_ctx_p->userparams, |
284 | 450k | dstack); |
285 | 450k | if (code >= 0) |
286 | 450k | code = set_user_params(i_ctx_p, &i_ctx_p->userparams); |
287 | 450k | r_set_space(system_dict, space); |
288 | 450k | if (lmem->save_level > 0) |
289 | 156k | alloc_set_in_save(idmemory); |
290 | 450k | estack_clear_cache(&iexec_stack); |
291 | 450k | dstack_set_top(&idict_stack); |
292 | 450k | return code; |
293 | 450k | } |
294 | | |
295 | | /* Store the interpreter state in a context. */ |
296 | | int |
297 | | context_state_store(gs_context_state_t * pcst) |
298 | 303k | { |
299 | 303k | ref_stack_cleanup(&pcst->dict_stack.stack); |
300 | 303k | ref_stack_cleanup(&pcst->exec_stack.stack); |
301 | 303k | ref_stack_cleanup(&pcst->op_stack.stack); |
302 | | /* |
303 | | * The user parameters in systemdict.userparams are kept |
304 | | * up to date by PostScript code, but we still need to save |
305 | | * systemdict.userparams to get the correct l_new flag. |
306 | | */ |
307 | 303k | { |
308 | 303k | ref *puserparams; |
309 | | /* We need i_ctx_p for access to the d_stack. */ |
310 | 303k | i_ctx_t *i_ctx_p = pcst; |
311 | | |
312 | 303k | if (dict_find_string(systemdict, "userparams", &puserparams) <= 0) |
313 | 0 | return_error(gs_error_Fatal); |
314 | 303k | pcst->userparams = *puserparams; |
315 | 303k | } |
316 | 0 | return 0; |
317 | 303k | } |
318 | | |
319 | | /* Free the contents of the state of a context, always to its local VM. */ |
320 | | /* Return a mask of which of its VMs, if any, we freed. */ |
321 | | int |
322 | | context_state_free(gs_context_state_t * pcst) |
323 | 0 | { |
324 | 0 | gs_ref_memory_t *mem = pcst->memory.space_local; |
325 | 0 | int freed = 0; |
326 | 0 | int i; |
327 | | |
328 | | /* |
329 | | * If this context is the last one referencing a particular VM |
330 | | * (local / global / system), free the entire VM space; |
331 | | * otherwise, just free the context-related structures. |
332 | | */ |
333 | 0 | for (i = countof(pcst->memory.spaces_indexed); --i >= 0;) { |
334 | 0 | if (pcst->memory.spaces_indexed[i] != 0 && |
335 | 0 | !--(pcst->memory.spaces_indexed[i]->num_contexts) |
336 | 0 | ) { |
337 | | /****** FREE THE ENTIRE SPACE ******/ |
338 | 0 | freed |= 1 << i; |
339 | 0 | } |
340 | 0 | } |
341 | | /* |
342 | | * If we freed any spaces at all, we must have freed the local |
343 | | * VM where the context structure and its substructures were |
344 | | * allocated. |
345 | | */ |
346 | 0 | if (freed) |
347 | 0 | return freed; |
348 | 0 | { |
349 | 0 | gs_gstate *pgs = pcst->pgs; |
350 | |
|
351 | 0 | gs_grestoreall(pgs); |
352 | | /* Patch the saved pointer so we can do the last grestore. */ |
353 | 0 | { |
354 | 0 | gs_gstate *saved = gs_gstate_saved(pgs); |
355 | |
|
356 | 0 | gs_gstate_swap_saved(saved, saved); |
357 | 0 | } |
358 | 0 | gs_grestore(pgs); |
359 | 0 | gs_gstate_swap_saved(pgs, (gs_gstate *) 0); |
360 | 0 | gs_gstate_free(pgs); |
361 | 0 | } |
362 | | /****** FREE USERPARAMS ******/ |
363 | 0 | gs_interp_free_stacks(mem, pcst); |
364 | 0 | return 0; |
365 | 0 | } |