/src/ghostpdl/pcl/pl/plparams.c
Line | Count | Source |
1 | | /* Copyright (C) 2001-2025 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* plparams.c - PJL handling of pdfwrite device parameters */ |
18 | | |
19 | | #include "std.h" |
20 | | #include "gsmemory.h" |
21 | | #include "gsmatrix.h" /* for gsdevice.h */ |
22 | | #include "gsdevice.h" |
23 | | #include "gsparam.h" |
24 | | #include "gp.h" |
25 | | #include "gserrors.h" |
26 | | #include "string_.h" |
27 | | #include "plparams.h" |
28 | | #include <stdlib.h> |
29 | | |
30 | | /*--------------------------------------------- pdfmark -------------------------------------------*/ |
31 | | |
32 | | /* Add a newly created param_string array to a param list, and then use that |
33 | | * param list as an argument to put the device parameters. |
34 | | */ |
35 | | static int pdfmark_write_list(gs_memory_t *mem, gx_device *device, gs_param_string_array *array_list) |
36 | 0 | { |
37 | 0 | gs_c_param_list list; |
38 | 0 | int code; |
39 | | |
40 | | /* Set the list to writeable, and initialise it */ |
41 | 0 | gs_c_param_list_write(&list, mem); |
42 | | /* We don't want keys to be persistent, as we are going to throw |
43 | | * away our array, force them to be copied |
44 | | */ |
45 | 0 | gs_param_list_set_persistent_keys((gs_param_list *) &list, false); |
46 | | |
47 | | /* Make really sure the list is writable, but don't initialise it */ |
48 | 0 | gs_c_param_list_write_more(&list); |
49 | | |
50 | | /* Add the param string array to the list */ |
51 | 0 | code = param_write_string_array((gs_param_list *)&list, "pdfmark", array_list); |
52 | 0 | if (code < 0) |
53 | 0 | return code; |
54 | | |
55 | | /* Set the param list back to readable, so putceviceparams can readit (mad...) */ |
56 | 0 | gs_c_param_list_read(&list); |
57 | | |
58 | | /* and set the actual device parameters */ |
59 | 0 | code = gs_putdeviceparams(device, (gs_param_list *)&list); |
60 | | |
61 | | /* release the memory allocated for the list parameter */ |
62 | 0 | gs_c_param_list_release(&list); |
63 | |
|
64 | 0 | return code; |
65 | 0 | } |
66 | | |
67 | | /* pdfmark operations always take an array parameter. Because (see below) we |
68 | | * know that array valuess must be homogenous types we can treat them all as |
69 | | * parameter strings. |
70 | | */ |
71 | | static int process_pdfmark(gs_memory_t *mem, gx_device *device, char *pdfmark) |
72 | 0 | { |
73 | 0 | char *p, *start, *copy, *stream_data = 0L; |
74 | 0 | int tokens = 0, code = 0; |
75 | 0 | gs_param_string *parray; |
76 | 0 | gs_param_string_array array_list; |
77 | 0 | bool putdict = false; |
78 | | |
79 | | /* Our parsing will alter the string contents, so copy it and perform the parsing on the copy */ |
80 | 0 | copy = (char *)gs_alloc_bytes(mem, strlen(pdfmark) + 1, "working buffer for pdfmark processing"); |
81 | 0 | if (copy == 0) |
82 | 0 | return -1; |
83 | 0 | strcpy(copy, pdfmark); |
84 | |
|
85 | 0 | start = copy + 1; |
86 | 0 | if (*pdfmark != '[') { |
87 | 0 | gs_free_object(mem, copy, "working buffer for pdfmark processing"); |
88 | 0 | return -1; |
89 | 0 | } |
90 | | |
91 | 0 | p = start; |
92 | 0 | while (*p != 0x00){ |
93 | 0 | if(*p == '(') { |
94 | 0 | while (*p != ')' && *p != 0x00) { |
95 | 0 | if (*p == '\\') |
96 | 0 | p++; |
97 | 0 | p++; |
98 | 0 | } |
99 | 0 | if (*p != ')') { |
100 | 0 | gs_free_object(mem, copy, "working buffer for pdfmark processing"); |
101 | 0 | return -1; |
102 | 0 | } |
103 | 0 | } else { |
104 | 0 | if (*p == ' ') { |
105 | 0 | tokens++; |
106 | 0 | } |
107 | 0 | } |
108 | 0 | p++; |
109 | 0 | } |
110 | | |
111 | 0 | if (*(p-1) != ' ') |
112 | 0 | tokens++; |
113 | | |
114 | | /* We need an extra one for a dummy CTM */ |
115 | 0 | tokens++; |
116 | |
|
117 | 0 | parray = (gs_param_string *)gs_alloc_bytes(mem, (size_t)tokens * sizeof(gs_param_string), "temporary pdfmark array"); |
118 | 0 | if (!parray) { |
119 | 0 | gs_free_object(mem, copy, "working buffer for pdfmark processing"); |
120 | 0 | return -1; |
121 | 0 | } |
122 | | |
123 | 0 | tokens = 0; |
124 | 0 | while (*start == ' ') |
125 | 0 | start++; |
126 | 0 | p = start; |
127 | |
|
128 | 0 | while (*p != 0x00){ |
129 | 0 | if(*p == '(') { |
130 | 0 | while (*p != ')' && *p != 0x00) { |
131 | 0 | if (*p == '\\') |
132 | 0 | p++; |
133 | 0 | p++; |
134 | 0 | } |
135 | 0 | if (*p != ')') { |
136 | 0 | gs_free_object(mem, copy, "working buffer for pdfmark processing"); |
137 | 0 | return -1; |
138 | 0 | } |
139 | 0 | } else { |
140 | 0 | if (*p == ' ') { |
141 | 0 | if (strncmp(start, "<<", 2) == 0) { |
142 | 0 | putdict = true; |
143 | 0 | } else { |
144 | 0 | if (strncmp(start, ">>", 2) != 0) { |
145 | 0 | *p = 0x00; |
146 | 0 | parray[tokens].data = (const byte *)start; |
147 | 0 | parray[tokens].size = strlen(start); |
148 | 0 | parray[tokens++].persistent = false; |
149 | 0 | } |
150 | 0 | } |
151 | 0 | start = ++p; |
152 | 0 | } else |
153 | 0 | p++; |
154 | 0 | } |
155 | 0 | } |
156 | 0 | if (*(p-1) != ' ') { |
157 | 0 | parray[tokens].data = (const byte *)start; |
158 | 0 | parray[tokens].size = strlen(start); |
159 | 0 | parray[tokens++].persistent = false; |
160 | 0 | } |
161 | | |
162 | | /* Move last entry up one and add a dummy CTM where it used to be */ |
163 | 0 | parray[tokens].data = parray[tokens - 1].data; |
164 | 0 | parray[tokens].size = parray[tokens - 1].size; |
165 | 0 | parray[tokens].persistent = parray[tokens - 1].persistent; |
166 | 0 | parray[tokens - 1].data = (const byte *)"[0 0 0 0 0 0]"; |
167 | 0 | parray[tokens - 1].size = 13; |
168 | 0 | parray[tokens - 1].persistent = false; |
169 | | |
170 | | /* Features are name objects (ie they start with a '/') but putdeviceparams wants them |
171 | | * as strings without the '/', so we need to strip that here. |
172 | | */ |
173 | 0 | if (parray[tokens].data[0] != '/') { |
174 | 0 | gs_free_object(mem, copy, "working buffer for pdfmark processing"); |
175 | 0 | gs_free_object(mem, parray, "temporary pdfmark array"); |
176 | 0 | return -1; |
177 | 0 | } else { |
178 | 0 | parray[tokens].data++; |
179 | 0 | parray[tokens].size--; |
180 | 0 | } |
181 | | |
182 | | /* We need to convert a 'PUT' with a dictonary into a 'PUTDICT', this is normally done |
183 | | * in PostScript |
184 | | */ |
185 | 0 | if (putdict && strncmp((const char *)(parray[tokens].data), "PUT", 3) == 0) { |
186 | 0 | parray[tokens].data = (const byte *)".PUTDICT"; |
187 | 0 | parray[tokens].size = 8; |
188 | 0 | parray[tokens].persistent = false; |
189 | 0 | } |
190 | | /* We also need some means to handle file data. Normally ths is done by creating a |
191 | | * PostScript file object and doing a 'PUT', but we can't do that, so we define a |
192 | | * special variety of 'PUT' called 'PUTFILE' and we handle that here. |
193 | | */ |
194 | 0 | if (strncmp((const char *)(parray[tokens].data), "PUTFILE", 7) == 0) { |
195 | 0 | gp_file *f; |
196 | 0 | char *filename; |
197 | 0 | int bytes; |
198 | |
|
199 | 0 | if (parray[tokens - 2].data[0] != '(') { |
200 | 0 | gs_free_object(mem, copy, "working buffer for pdfmark processing"); |
201 | 0 | gs_free_object(mem, parray, "temporary pdfmark array"); |
202 | 0 | return -1; |
203 | 0 | } |
204 | 0 | filename = (char *)&(parray[tokens - 2].data[1]); |
205 | 0 | filename[strlen(filename) - 1] = 0x00; |
206 | |
|
207 | 0 | f = gp_fopen(mem, (const char *)filename, "rb"); |
208 | 0 | if (!f) { |
209 | 0 | gs_free_object(mem, copy, "working buffer for pdfmark processing"); |
210 | 0 | gs_free_object(mem, parray, "temporary pdfmark array"); |
211 | 0 | return -1; |
212 | 0 | } |
213 | | |
214 | 0 | if (gp_fseek(f, 0, SEEK_END) != 0) { |
215 | 0 | gs_free_object(mem, copy, "working buffer for pdfmark processing"); |
216 | 0 | gs_free_object(mem, parray, "temporary pdfmark array"); |
217 | 0 | gp_fclose(f); |
218 | 0 | return -1; |
219 | 0 | } |
220 | 0 | bytes = gp_ftell(f); |
221 | 0 | if (bytes < 0) { |
222 | 0 | gs_free_object(mem, copy, "working buffer for pdfmark processing"); |
223 | 0 | gs_free_object(mem, parray, "temporary pdfmark array"); |
224 | 0 | gp_fclose(f); |
225 | 0 | return -1; |
226 | 0 | } |
227 | | |
228 | 0 | parray[tokens - 2].data = (const byte *)gs_alloc_bytes(mem, bytes, "PJL pdfmark, stream"); |
229 | 0 | if (!parray[tokens - 2].data) { |
230 | 0 | gs_free_object(mem, copy, "working buffer for pdfmark processing"); |
231 | 0 | gs_free_object(mem, parray, "temporary pdfmark array"); |
232 | 0 | gp_fclose(f); |
233 | 0 | return -1; |
234 | 0 | } |
235 | 0 | stream_data = (char *)(parray[tokens - 2].data); |
236 | |
|
237 | 0 | if (gp_fseek(f, 0, SEEK_SET) != 0) { |
238 | 0 | gs_free_object(mem, stream_data, "PJL pdfmark, stream"); |
239 | 0 | gs_free_object(mem, copy, "working buffer for pdfmark processing"); |
240 | 0 | gs_free_object(mem, parray, "temporary pdfmark array"); |
241 | 0 | gp_fclose(f); |
242 | 0 | return gs_note_error(gs_error_ioerror); |
243 | 0 | } |
244 | 0 | code = gp_fread(stream_data, 1, bytes, f); |
245 | 0 | if (code != bytes) { |
246 | 0 | gs_free_object(mem, stream_data, "PJL pdfmark, stream"); |
247 | 0 | gs_free_object(mem, copy, "working buffer for pdfmark processing"); |
248 | 0 | gs_free_object(mem, parray, "temporary pdfmark array"); |
249 | 0 | gp_fclose(f); |
250 | 0 | return gs_note_error(gs_error_ioerror); |
251 | 0 | } |
252 | 0 | gp_fclose(f); |
253 | 0 | parray[tokens - 2].size = bytes; |
254 | |
|
255 | 0 | parray[tokens].data = (const byte *)".PUTSTREAM"; |
256 | 0 | parray[tokens].size = 10; |
257 | 0 | parray[tokens].persistent = false; |
258 | 0 | } |
259 | | |
260 | 0 | array_list.data = parray; |
261 | 0 | array_list.persistent = 0; |
262 | 0 | array_list.size = ++tokens; |
263 | |
|
264 | 0 | code = pdfmark_write_list(mem, device, &array_list); |
265 | |
|
266 | 0 | if (stream_data) |
267 | 0 | gs_free_object(mem, stream_data, "PJL pdfmark, stream"); |
268 | 0 | gs_free_object(mem, copy, "working buffer for pdfmark processing"); |
269 | 0 | gs_free_object(mem, parray, "temporary pdfmark array"); |
270 | |
|
271 | 0 | return code; |
272 | 0 | } |
273 | | |
274 | | int pcl_pjl_pdfmark(gs_memory_t *mem, gx_device *device, char *pdfmark) |
275 | 0 | { |
276 | 0 | char *pdfmark_start, *token_start, end, *p; |
277 | 0 | int code; |
278 | |
|
279 | 0 | p = token_start = pdfmark_start = pdfmark + 1; |
280 | |
|
281 | 0 | do { |
282 | 0 | while (*p != ' ' && *p != '"' && *p != 0x00) |
283 | 0 | p++; |
284 | 0 | if((p - token_start) != 7 || strncmp(token_start, "pdfmark", 7) != 0){ |
285 | 0 | if (*p != 0x00) |
286 | 0 | token_start = ++p; |
287 | 0 | else |
288 | 0 | break; |
289 | 0 | } else { |
290 | 0 | token_start--; |
291 | 0 | end = *token_start; |
292 | 0 | *token_start = 0x00; |
293 | 0 | code = process_pdfmark(mem, device, pdfmark_start); |
294 | 0 | if (code < 0) |
295 | 0 | return code; |
296 | | |
297 | 0 | *token_start = end; |
298 | 0 | token_start = pdfmark_start = ++p; |
299 | 0 | } |
300 | 0 | } while (*p != 0x00); |
301 | 0 | return 0; |
302 | 0 | } |
303 | | |
304 | | /*--------------------------------------------- distillerparams -------------------------------------------*/ |
305 | | |
306 | | int pcl_pjl_setdistillerparams(gs_memory_t *mem, gx_device *device, char *distillerparams) |
307 | 0 | { |
308 | 0 | char *p, *start, *copy; |
309 | 0 | int code = 0; |
310 | 0 | gs_c_param_list *plist; |
311 | |
|
312 | 0 | plist = gs_c_param_list_alloc(mem, "temp C param list for PJL distillerparams"); |
313 | 0 | if (plist == NULL) |
314 | 0 | return -1; |
315 | 0 | gs_c_param_list_write(plist, mem); |
316 | 0 | gs_param_list_set_persistent_keys((gs_param_list *) plist, false); |
317 | 0 | gs_c_param_list_write_more(plist); |
318 | | |
319 | | /* Our parsing will alter the string contents, so copy it and perform the parsing on the copy */ |
320 | 0 | copy = (char *)gs_alloc_bytes(mem, strlen(distillerparams) + 1, "working buffer for distillerparams processing"); |
321 | 0 | if (copy == 0) |
322 | 0 | return -1; |
323 | 0 | strcpy(copy, distillerparams); |
324 | |
|
325 | 0 | if (*copy == '"') { |
326 | 0 | start = copy + 1; |
327 | 0 | copy[strlen(copy) - 1] = 0x00; |
328 | 0 | } |
329 | 0 | else |
330 | 0 | start = copy; |
331 | |
|
332 | 0 | if (*start != '<' || start[1] != '<') { |
333 | 0 | gs_free_object(mem, copy, "working buffer for distillerparams processing"); |
334 | 0 | return -1; |
335 | 0 | } |
336 | 0 | start += 2; |
337 | |
|
338 | 0 | if (copy[strlen(copy) - 1] != '>' || copy[strlen(copy) - 2] != '>') { |
339 | 0 | gs_free_object(mem, copy, "working buffer for distillerparams processing"); |
340 | 0 | return -1; |
341 | 0 | } |
342 | 0 | copy[strlen(copy) - 2] = 0x00; |
343 | |
|
344 | 0 | while (*start == ' ') |
345 | 0 | start++; |
346 | 0 | p = start; |
347 | | |
348 | | /* Parse the string, adding what we find to the plist */ |
349 | 0 | code = gs_param_list_add_tokens((gs_param_list *)plist, p); |
350 | 0 | if (code < 0) { |
351 | 0 | gs_c_param_list_release(plist); |
352 | 0 | return code; |
353 | 0 | } |
354 | | |
355 | | /* Discard our working copy of the string */ |
356 | 0 | gs_free_object(mem, copy, "working buffer for distillerparams processing"); |
357 | | |
358 | | /* Set the list to 'read' (bonkers...) */ |
359 | 0 | gs_c_param_list_read(plist); |
360 | | |
361 | | /* Actually set the newly created device parameters */ |
362 | 0 | code = gs_putdeviceparams(device, (gs_param_list *)plist); |
363 | | |
364 | | /* And throw away the plist, we're done with it */ |
365 | 0 | gs_c_param_list_release(plist); |
366 | 0 | return code; |
367 | 0 | } |