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