/src/ghostpdl/base/gxclpage.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2024 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 | | /* Page object management */ |
18 | | #include "gdevprn.h" |
19 | | #include "gdevdevn.h" |
20 | | #include "gxcldev.h" |
21 | | #include "gxclpage.h" |
22 | | #include "gsicc_cache.h" |
23 | | #include "gsparams.h" |
24 | | #include "string_.h" |
25 | | #include <ctype.h> /* for isalpha, etc. */ |
26 | | |
27 | | extern dev_proc_open_device(clist_open); |
28 | | |
29 | | /* Save the current clist state into a saved page structure, |
30 | | * and optionally stashes the files into the given save_files |
31 | | * pointers. |
32 | | * Does NOT alter the clist files. */ |
33 | | /* RJW: Does too. The opendevice call at the end calls clist_open */ |
34 | | static int |
35 | | do_page_save(gx_device_printer * pdev, gx_saved_page * page, clist_file_ptr *save_files) |
36 | 0 | { |
37 | 0 | gx_device_clist *cdev = (gx_device_clist *) pdev; |
38 | 0 | gx_device_clist_writer * const pcldev = (gx_device_clist_writer *)pdev; |
39 | 0 | int code; |
40 | 0 | gs_c_param_list paramlist; |
41 | 0 | gs_devn_params *pdevn_params; |
42 | | |
43 | | /* Save the device information. */ |
44 | 0 | strncpy(page->dname, pdev->dname, sizeof(page->dname)-1); |
45 | 0 | page->color_info = pdev->color_info; |
46 | 0 | page->tag = pdev->graphics_type_tag; |
47 | 0 | page->io_procs = cdev->common.page_info.io_procs; |
48 | | /* Save the page information. */ |
49 | 0 | memcpy(page->cfname, pcldev->page_info.cfname, sizeof(page->cfname)); |
50 | 0 | memcpy(page->bfname, pcldev->page_info.bfname, sizeof(page->bfname)); |
51 | 0 | page->bfile_end_pos = pcldev->page_info.bfile_end_pos; |
52 | 0 | if (save_files != NULL) { |
53 | 0 | save_files[0] = pcldev->page_info.cfile; |
54 | 0 | save_files[1] = pcldev->page_info.bfile; |
55 | 0 | pcldev->page_info.cfile = NULL; |
56 | 0 | pcldev->page_info.bfile = NULL; |
57 | 0 | } |
58 | 0 | pcldev->page_info.cfname[0] = 0; |
59 | 0 | pcldev->page_info.bfname[0] = 0; |
60 | 0 | page->tile_cache_size = pcldev->page_info.tile_cache_size; |
61 | 0 | page->line_ptrs_offset = pcldev->page_info.line_ptrs_offset; |
62 | 0 | page->num_planar_planes = pcldev->num_planar_planes; |
63 | 0 | page->band_params = pcldev->page_info.band_params; |
64 | | /* Now serialize and save the rest of the information from the device params */ |
65 | | /* we count on this to correctly set the color_info, devn_params and icc_struct */ |
66 | 0 | page->mem = pdev->memory->non_gc_memory; |
67 | 0 | gs_c_param_list_write(¶mlist, pdev->memory); |
68 | 0 | if ((code = gs_getdeviceparams((gx_device *)pdev, (gs_param_list *)¶mlist)) < 0) { |
69 | 0 | goto params_out; |
70 | 0 | } |
71 | | /* fetch bytes needed for param list */ |
72 | 0 | gs_c_param_list_read(¶mlist); |
73 | 0 | if ((code = gs_param_list_serialize((gs_param_list *)¶mlist, NULL, 0)) < 0) { |
74 | 0 | goto params_out; |
75 | 0 | } |
76 | 0 | page->paramlist_len = code; |
77 | 0 | if ((page->paramlist = gs_alloc_bytes(page->mem, |
78 | 0 | page->paramlist_len, |
79 | 0 | "saved_page paramlist")) == NULL) { |
80 | 0 | code = gs_error_VMerror; |
81 | 0 | goto params_out; |
82 | 0 | } |
83 | 0 | code = gs_param_list_serialize((gs_param_list *)¶mlist, page->paramlist, |
84 | 0 | page->paramlist_len); |
85 | 0 | params_out: |
86 | 0 | gs_c_param_list_release(¶mlist); |
87 | 0 | if (code < 0) |
88 | 0 | return code; /* all device param errors collect here */ |
89 | | |
90 | | /* Save other information. */ |
91 | | /* If this device has spot colors that were added dynamically, we need to pass the names */ |
92 | | /* through as well. These are from the devn_params->separations->names array. */ |
93 | 0 | if ((pdevn_params = dev_proc(pdev, ret_devn_params)((gx_device *)pdev)) != NULL) { |
94 | 0 | int i; |
95 | |
|
96 | 0 | page->num_separations = pdevn_params->separations.num_separations; |
97 | 0 | for (i=0; i < page->num_separations; i++) { |
98 | 0 | page->separation_name_sizes[i] = pdevn_params->separations.names[i].size; |
99 | 0 | page->separation_names[i] = gs_alloc_bytes(page->mem, page->separation_name_sizes[i], |
100 | 0 | "saved_page separation_names"); |
101 | 0 | if (page->separation_names[i] == NULL) { |
102 | 0 | gs_free_object(page->mem, page->paramlist, "saved_page paramlist"); |
103 | 0 | while (--i > 0) |
104 | 0 | gs_free_object(page->mem, page->separation_names[i], |
105 | 0 | "saved_page separation_names"); |
106 | 0 | return gs_error_VMerror; |
107 | 0 | } |
108 | 0 | memcpy(page->separation_names[i], pdevn_params->separations.names[i].data, |
109 | 0 | page->separation_name_sizes[i]); |
110 | 0 | } |
111 | 0 | } |
112 | | /* Now re-open the clist device so that we get new files for the next page */ |
113 | 0 | return clist_open((gx_device *) pdev); |
114 | 0 | } |
115 | | |
116 | | /* Save a page. The elements are allocated by this function in non_gc_memory */ |
117 | | int |
118 | | gdev_prn_save_page(gx_device_printer * pdev, gx_saved_page * page) |
119 | 0 | { |
120 | 0 | gx_device_clist *cdev = (gx_device_clist *) pdev; |
121 | 0 | gx_device_clist_writer * const pcldev = (gx_device_clist_writer *)pdev; |
122 | 0 | int code; |
123 | | |
124 | | /* Make sure we are banding. */ |
125 | 0 | if (!PRINTER_IS_CLIST(pdev)) |
126 | 0 | return_error(gs_error_rangecheck); |
127 | | |
128 | 0 | if ((code = clist_end_page(pcldev)) < 0 || |
129 | 0 | (code = cdev->common.page_info.io_procs->fclose(pcldev->page_info.cfile, pcldev->page_info.cfname, false)) < 0 || |
130 | 0 | (code = cdev->common.page_info.io_procs->fclose(pcldev->page_info.bfile, pcldev->page_info.bfname, false)) < 0 |
131 | 0 | ) |
132 | 0 | return code; |
133 | 0 | return do_page_save(pdev, page, NULL); |
134 | 0 | } |
135 | | |
136 | | /* Render an array of saved pages. */ |
137 | | int |
138 | | gdev_prn_render_pages(gx_device_printer * pdev, |
139 | | const gx_placed_page * ppages, int count) |
140 | 0 | { |
141 | 0 | gx_device_clist_reader * const pcldev = |
142 | 0 | (gx_device_clist_reader *)pdev; |
143 | | |
144 | | /* Check to make sure the pages are compatible with the device. */ |
145 | 0 | { |
146 | 0 | int i; |
147 | |
|
148 | 0 | for (i = 0; i < count; ++i) { |
149 | 0 | const gx_saved_page *page = ppages[i].page; |
150 | | |
151 | | /* We would like to fully check the color representation, */ |
152 | | /* but we don't have enough information to do that. */ |
153 | 0 | if (strcmp(page->dname, pdev->dname) != 0 || |
154 | 0 | !gx_color_info_equal(&page->color_info, &pdev->color_info) |
155 | 0 | ) |
156 | 0 | return_error(gs_error_rangecheck); |
157 | | /* Currently we don't allow translation in Y. */ |
158 | 0 | if (ppages[i].offset.y != 0) |
159 | 0 | return_error(gs_error_rangecheck); |
160 | | /* Make sure the band parameters are compatible. */ |
161 | 0 | if (page->band_params.BandBufferSpace != |
162 | 0 | pdev->buffer_space || |
163 | 0 | page->band_params.BandWidth != |
164 | 0 | pdev->width |
165 | 0 | ) |
166 | 0 | return_error(gs_error_rangecheck); |
167 | | /* Currently we require all band heights to be the same. */ |
168 | 0 | if (i > 0 && page->band_params.BandHeight != |
169 | 0 | ppages[0].page->band_params.BandHeight) |
170 | 0 | return_error(gs_error_rangecheck); |
171 | 0 | } |
172 | 0 | } |
173 | | /* Set up the page list in the device. */ |
174 | | /****** SHOULD FACTOR THIS OUT OF clist_render_init ******/ |
175 | 0 | pcldev->ymin = pcldev->ymax = 0; |
176 | 0 | pcldev->pages = ppages; |
177 | 0 | pcldev->num_pages = count; |
178 | 0 | pcldev->offset_map = NULL; |
179 | 0 | pcldev->icc_table = NULL; /* FIXME: output_page doesn't load these */ |
180 | 0 | pcldev->icc_cache_cl = NULL; /* FIXME: output_page doesn't load these */ |
181 | | /* Render the pages. */ |
182 | 0 | { |
183 | 0 | int code = (*dev_proc(pdev, output_page)) |
184 | 0 | ((gx_device *) pdev, (pdev->IgnoreNumCopies || pdev->NumCopies_set <= 0) ? 1 : pdev->NumCopies, true); |
185 | | |
186 | | /* Delete the temporary files and free the paramlist. */ |
187 | 0 | int i; |
188 | |
|
189 | 0 | for (i = 0; i < count; ++i) { |
190 | 0 | gx_saved_page *page = ppages[i].page; |
191 | |
|
192 | 0 | pcldev->page_info.io_procs->unlink(page->cfname); |
193 | 0 | pcldev->page_info.io_procs->unlink(page->bfname); |
194 | 0 | gs_free_object(page->mem, page->paramlist, "gdev_prn_render_pages"); |
195 | 0 | page->paramlist = NULL; |
196 | 0 | } |
197 | 0 | return code; |
198 | 0 | } |
199 | 0 | } |
200 | | |
201 | | /* |
202 | | * Allocate and initialize the list structure |
203 | | */ |
204 | | gx_saved_pages_list * |
205 | | gx_saved_pages_list_new(gx_device_printer *pdev) |
206 | 0 | { |
207 | 0 | gx_saved_pages_list *newlist; |
208 | 0 | gs_memory_t *non_gc_mem = pdev->memory->non_gc_memory; |
209 | |
|
210 | 0 | if ((newlist = |
211 | 0 | (gx_saved_pages_list *)gs_alloc_bytes(non_gc_mem, |
212 | 0 | sizeof(gx_saved_pages_list), |
213 | 0 | "gx_saved_pages_list_new")) == NULL) |
214 | 0 | return NULL; |
215 | | |
216 | 0 | memset(newlist, 0, sizeof(gx_saved_pages_list)); |
217 | 0 | newlist->mem = non_gc_mem; |
218 | 0 | newlist->PageCount = pdev->PageCount; /* PageCount when list created */ |
219 | 0 | newlist->collated_copies = 1; |
220 | 0 | return newlist; |
221 | 0 | } |
222 | | |
223 | | /* |
224 | | * Add a new saved page to the end of an in memory list. Refer to the |
225 | | * documentation for gx_saved_pages_list. This allocates the saved_ |
226 | | * page as well as the saved_pages_list_element and relies on the |
227 | | * gdev_prn_save_page to use non_gc_memory since this list is never |
228 | | * in GC memory. |
229 | | */ |
230 | | int |
231 | | gx_saved_pages_list_add(gx_device_printer * pdev) |
232 | 0 | { |
233 | 0 | gx_saved_pages_list *list = pdev->saved_pages_list; |
234 | 0 | gx_saved_pages_list_element *new_list_element; |
235 | 0 | gx_saved_page *newpage; |
236 | 0 | int code; |
237 | |
|
238 | 0 | if ((newpage = |
239 | 0 | (gx_saved_page *)gs_alloc_bytes(list->mem, |
240 | 0 | sizeof(gx_saved_page), |
241 | 0 | "gx_saved_pages_list_add")) == NULL) |
242 | 0 | return_error (gs_error_VMerror); |
243 | | |
244 | 0 | if ((new_list_element = |
245 | 0 | (gx_saved_pages_list_element *)gs_alloc_bytes(list->mem, |
246 | 0 | sizeof(gx_saved_pages_list_element), |
247 | 0 | "gx_saved_pages_list_add")) == NULL) { |
248 | 0 | gs_free_object(list->mem, newpage, "gx_saved_pages_list_add"); |
249 | 0 | return_error (gs_error_VMerror); |
250 | 0 | } |
251 | | |
252 | 0 | if ((code = gdev_prn_save_page(pdev, newpage)) < 0) { |
253 | 0 | gs_free_object(list->mem, new_list_element, "gx_saved_pages_list_add"); |
254 | 0 | gs_free_object(list->mem, newpage, "gx_saved_pages_list_add"); |
255 | 0 | return code; |
256 | 0 | } |
257 | 0 | new_list_element->sequence_number = ++list->count; |
258 | 0 | new_list_element->page = newpage; |
259 | 0 | new_list_element->next = NULL; |
260 | 0 | if (list->tail == NULL) { |
261 | | /* list was empty, start it */ |
262 | 0 | new_list_element->prev = NULL; |
263 | 0 | list->head = list->tail = new_list_element; |
264 | 0 | } else { |
265 | | /* place as new tail */ |
266 | 0 | new_list_element->prev = list->tail; |
267 | 0 | list->tail->next = new_list_element; |
268 | 0 | list->tail = new_list_element; |
269 | 0 | } |
270 | 0 | return 0; /* success */ |
271 | 0 | } |
272 | | |
273 | | /* Free the contents of all saved pages, unlink the files and free the |
274 | | * saved_page structures. Does not free the gx_saved_pages_list struct. |
275 | | */ |
276 | | void |
277 | | gx_saved_pages_list_free(gx_saved_pages_list *list) |
278 | 0 | { |
279 | 0 | gx_saved_pages_list_element *curr_elem = list->head; |
280 | 0 | while (curr_elem != NULL) { |
281 | 0 | gx_saved_page *curr_page; |
282 | 0 | gx_saved_pages_list_element *next_elem; |
283 | |
|
284 | 0 | curr_page = curr_elem->page; |
285 | 0 | curr_page->io_procs->unlink(curr_page->cfname); |
286 | 0 | curr_page->io_procs->unlink(curr_page->bfname); |
287 | 0 | gs_free_object(curr_page->mem, curr_page->paramlist, "gx_saved_pages_list_free"); |
288 | 0 | gs_free_object(list->mem, curr_page, "gx_saved_pages_list_free"); |
289 | |
|
290 | 0 | next_elem = curr_elem->next; |
291 | 0 | gs_free_object(list->mem, curr_elem, "gx_saved_pages_list_free"); |
292 | 0 | curr_elem = next_elem; |
293 | 0 | }; |
294 | | |
295 | | /* finally free the list itself */ |
296 | 0 | gs_free_object(list->mem, list, "gx_saved_pages_list_free"); |
297 | 0 | } |
298 | | |
299 | | |
300 | | /* This enum has to be in the same order as saved_pages_keys */ |
301 | | typedef enum { |
302 | | PARAM_UNKNOWN = 0, |
303 | | PARAM_BEGIN, |
304 | | PARAM_END, |
305 | | PARAM_FLUSH, |
306 | | PARAM_PRINT, |
307 | | PARAM_COPIES, |
308 | | PARAM_NORMAL, |
309 | | PARAM_REVERSE, |
310 | | PARAM_EVEN, |
311 | | PARAM_EVEN0PAD, |
312 | | PARAM_ODD, |
313 | | /* any new keywords precede these */ |
314 | | PARAM_NUMBER, |
315 | | PARAM_DASH, |
316 | | PARAM_STAR |
317 | | } saved_pages_key_enum; |
318 | | |
319 | | static saved_pages_key_enum |
320 | | param_find_key(byte *token, int token_size) |
321 | 0 | { |
322 | 0 | int i; |
323 | 0 | static const char *saved_pages_keys[] = { |
324 | 0 | "begin", "end", "flush", "print", "copies", "normal", "reverse", "even", "even0pad", "odd" |
325 | 0 | }; |
326 | 0 | saved_pages_key_enum found = PARAM_UNKNOWN; |
327 | |
|
328 | 0 | if (*token >= '0' && *token <= '9') |
329 | 0 | return PARAM_NUMBER; |
330 | 0 | if (*token == '-') |
331 | 0 | return PARAM_DASH; |
332 | 0 | if (*token == (byte)'*') |
333 | 0 | return PARAM_STAR; |
334 | | |
335 | 0 | for (i=0; i < (sizeof(saved_pages_keys)/sizeof(saved_pages_keys[0])); i++) { |
336 | 0 | if (strncasecmp((char *)token, saved_pages_keys[i], token_size) == 0) { |
337 | 0 | found = (saved_pages_key_enum) (i + 1); |
338 | 0 | break; |
339 | 0 | } |
340 | 0 | } |
341 | 0 | return found; |
342 | 0 | } |
343 | | |
344 | | /* Find next token, skipping any leading whitespace or non-alphanumeric */ |
345 | | /* Returns pointer to next token and updates 'token_size'. Caller can */ |
346 | | /* use (token - param) + token_size to update to next token in the */ |
347 | | /* param string (param) and remaining char count (param_left) */ |
348 | | /* Returns NULL and token_size =0 if no more alphanumeric tokens */ |
349 | | static byte * |
350 | | param_parse_token(byte *param, int param_left, int *token_size) |
351 | 0 | { |
352 | 0 | int token_len = 0; |
353 | 0 | byte *token = param; |
354 | 0 | bool single_char_token = true; |
355 | | |
356 | | /* skip leading junk */ |
357 | 0 | while (param_left > 0) { |
358 | 0 | if (isalnum(*token)) { |
359 | 0 | single_char_token = false; /* we'll scan past this keyword */ |
360 | 0 | break; |
361 | 0 | } |
362 | 0 | if (*token == (byte)'-') /* valid in page range */ |
363 | 0 | break; |
364 | 0 | if (*token == (byte)'*') /* valid in page range */ |
365 | 0 | break; |
366 | | /* skip any other junk */ |
367 | 0 | token++; |
368 | 0 | param_left--; |
369 | 0 | } |
370 | 0 | if (param_left == 0) { |
371 | 0 | *token_size = 0; /* no token found */ |
372 | 0 | return NULL; /* No more items */ |
373 | 0 | } |
374 | 0 | if (single_char_token) { |
375 | 0 | param_left--; /* we've consumed one character */ |
376 | 0 | *token_size = 1; |
377 | 0 | return token; |
378 | 0 | } |
379 | | |
380 | | /* token points to start, skip valid alphanumeric characters after */ |
381 | | /* the first. Single character tokens terminate this scan. */ |
382 | 0 | while (param_left > 0) { |
383 | 0 | if (!isalnum(token[token_len])) |
384 | 0 | break; |
385 | 0 | token_len++; |
386 | 0 | param_left--; |
387 | 0 | } |
388 | 0 | *token_size = token_len; |
389 | 0 | return token; |
390 | 0 | } |
391 | | |
392 | | static int |
393 | | do_page_load(gx_device_printer *pdev, gx_saved_page *page, clist_file_ptr *save_files) |
394 | 0 | { |
395 | 0 | int code; |
396 | 0 | gx_device_clist_reader *crdev = (gx_device_clist_reader *)pdev; |
397 | 0 | gs_c_param_list paramlist; |
398 | 0 | gs_devn_params *pdevn_params; |
399 | | |
400 | | /* if this is a DeviceN device (that supports spot colors), we need to load the */ |
401 | | /* devn_params saved in the page (num_separations, separations[]) */ |
402 | 0 | if ((pdevn_params = dev_proc(pdev, ret_devn_params)((gx_device *)pdev)) != NULL) { |
403 | 0 | int i; |
404 | |
|
405 | 0 | pdevn_params->separations.num_separations = page->num_separations; |
406 | 0 | for (i=0; i < page->num_separations; i++) { |
407 | 0 | pdevn_params->separations.names[i].size = page->separation_name_sizes[i]; |
408 | 0 | pdevn_params->separations.names[i].data = gs_alloc_bytes(pdev->memory->stable_memory, |
409 | 0 | page->separation_name_sizes[i], |
410 | 0 | "saved_page separation_names"); |
411 | 0 | if (pdevn_params->separations.names[i].data == NULL) { |
412 | 0 | while (--i > 0) |
413 | 0 | gs_free_object(pdev->memory->stable_memory, |
414 | 0 | pdevn_params->separations.names[i].data, |
415 | 0 | "saved_page separation_names"); |
416 | 0 | code = gs_error_VMerror; |
417 | 0 | goto out; |
418 | 0 | } |
419 | 0 | memcpy(pdevn_params->separations.names[i].data, page->separation_names[i], |
420 | 0 | page->separation_name_sizes[i]); |
421 | 0 | } |
422 | 0 | } |
423 | | /* fetch and put the params we saved with the page */ |
424 | 0 | gs_c_param_list_write(¶mlist, pdev->memory); |
425 | 0 | if ((code = gs_param_list_unserialize((gs_param_list *)¶mlist, page->paramlist)) < 0) |
426 | 0 | goto out; |
427 | 0 | gs_c_param_list_read(¶mlist); |
428 | 0 | code = gs_putdeviceparams((gx_device *)pdev, (gs_param_list *)¶mlist); |
429 | 0 | gs_c_param_list_release(¶mlist); |
430 | 0 | if (code < 0) { |
431 | 0 | goto out; |
432 | 0 | } |
433 | 0 | if (code > 0) |
434 | 0 | if ((code = gs_opendevice((gx_device *)pdev)) < 0) |
435 | 0 | goto out; |
436 | | |
437 | | /* If the device is now a writer, that means putparams realloced the device */ |
438 | | /* so we need to get back to reader mode and remove the extra clist files */ |
439 | 0 | if (CLIST_IS_WRITER((gx_device_clist *)pdev)) { |
440 | 0 | if ((code = clist_close_writer_and_init_reader((gx_device_clist *)crdev)) < 0) |
441 | 0 | goto out; |
442 | | /* close and unlink the temp files just created */ |
443 | 0 | if (crdev->page_info.cfile != NULL) |
444 | 0 | crdev->page_info.io_procs->fclose(crdev->page_info.cfile, crdev->page_info.cfname, true); |
445 | 0 | if (crdev->page_info.bfile != NULL) |
446 | 0 | crdev->page_info.io_procs->fclose(crdev->page_info.bfile, crdev->page_info.bfname, true); |
447 | 0 | crdev->page_info.cfile = crdev->page_info.bfile = NULL; |
448 | 0 | } |
449 | | |
450 | | /* set up the page_info, after putdeviceparams that may have changed things */ |
451 | 0 | crdev->page_info.io_procs = page->io_procs; |
452 | 0 | crdev->page_info.tile_cache_size = page->tile_cache_size; |
453 | 0 | crdev->page_info.bfile_end_pos = page->bfile_end_pos; |
454 | 0 | crdev->page_info.band_params = page->band_params; |
455 | 0 | crdev->graphics_type_tag = page->tag; |
456 | 0 | crdev->page_info.line_ptrs_offset = page->line_ptrs_offset; |
457 | 0 | crdev->num_planar_planes = page->num_planar_planes; |
458 | |
|
459 | 0 | crdev->yplane.index = -1; |
460 | 0 | crdev->pages = NULL; |
461 | 0 | crdev->num_pages = 1; /* single page at a time */ |
462 | 0 | crdev->offset_map = NULL; |
463 | 0 | crdev->render_threads = NULL; |
464 | 0 | crdev->ymin = crdev->ymax = 0; /* invalidate buffer contents to force rasterizing */ |
465 | | |
466 | | /* We probably don't need to copy in the filenames, but do it in case something expects it */ |
467 | 0 | memcpy(crdev->page_info.cfname, page->cfname, sizeof(crdev->page_info.cfname)); |
468 | 0 | memcpy(crdev->page_info.bfname, page->bfname, sizeof(crdev->page_info.bfname)); |
469 | 0 | if (save_files != NULL) |
470 | 0 | { |
471 | 0 | crdev->page_info.cfile = save_files[0]; |
472 | 0 | crdev->page_info.bfile = save_files[1]; |
473 | 0 | } |
474 | 0 | out: |
475 | 0 | return code; |
476 | 0 | } |
477 | | |
478 | | static int |
479 | | gx_saved_page_load(gx_device_printer *pdev, gx_saved_page *page) |
480 | 0 | { |
481 | 0 | int code; |
482 | 0 | gx_device_clist_reader *crdev = (gx_device_clist_reader *)pdev; |
483 | |
|
484 | 0 | code = do_page_load(pdev, page, NULL); |
485 | 0 | if (code < 0) |
486 | 0 | return code; |
487 | | |
488 | | /* Now open this page's files */ |
489 | 0 | code = crdev->page_info.io_procs->fopen(crdev->page_info.cfname, |
490 | 0 | gp_fmode_rb, &(crdev->page_info.cfile), crdev->bandlist_memory, |
491 | 0 | crdev->bandlist_memory, true); |
492 | 0 | if (code >= 0) { |
493 | 0 | code = crdev->page_info.io_procs->fopen(crdev->page_info.bfname, |
494 | 0 | gp_fmode_rb, &(crdev->page_info.bfile), crdev->bandlist_memory, |
495 | 0 | crdev->bandlist_memory, false); |
496 | 0 | } |
497 | |
|
498 | 0 | return code; |
499 | 0 | } |
500 | | |
501 | | static int |
502 | | gx_output_saved_page(gx_device_printer *pdev, gx_saved_page *page) |
503 | 0 | { |
504 | 0 | int code, ecode; |
505 | | /* Note that banding_type is NOT a device parameter handled in the paramlist */ |
506 | 0 | gdev_banding_type save_banding_type = pdev->space_params.banding_type; |
507 | 0 | gx_device_clist_reader *crdev = (gx_device_clist_reader *)pdev; |
508 | |
|
509 | 0 | pdev->space_params.banding_type = BandingAlways; |
510 | |
|
511 | 0 | if ((code = gx_saved_page_load(pdev, page)) < 0) |
512 | 0 | goto out; |
513 | | |
514 | | /* don't want the band files touched after printing */ |
515 | 0 | crdev->do_not_open_or_close_bandfiles = true; |
516 | | |
517 | | /* load the color_usage_array */ |
518 | 0 | if ((code = clist_read_color_usage_array(crdev)) < 0) |
519 | 0 | goto out; |
520 | 0 | if ((code = clist_read_icctable(crdev)) < 0) |
521 | 0 | goto out; |
522 | 0 | code = (crdev->icc_cache_cl = gsicc_cache_new(crdev->memory)) == NULL ? |
523 | 0 | gs_error_VMerror : code; |
524 | 0 | if (code < 0) |
525 | 0 | goto out; |
526 | | |
527 | | /* After setting params, make sure bg_printing is off */ |
528 | 0 | pdev->bg_print_requested = false; |
529 | | |
530 | | /* Note: we never flush pages allowing for re-printing from the list */ |
531 | | /* data (files) will be deleted when the list is flushed or freed. */ |
532 | 0 | code = (*dev_proc(pdev, output_page)) ((gx_device *) pdev, |
533 | 0 | (pdev->IgnoreNumCopies || pdev->NumCopies_set <= 0) ? 1 : pdev->NumCopies, false); |
534 | |
|
535 | 0 | clist_free_icc_table(crdev->icc_table, crdev->memory); |
536 | 0 | crdev->icc_table = NULL; |
537 | 0 | rc_decrement(crdev->icc_cache_cl,"clist_finish_page"); |
538 | 0 | crdev->icc_cache_cl = NULL; |
539 | | |
540 | | /* Close the clist files */ |
541 | 0 | ecode = crdev->page_info.io_procs->fclose(crdev->page_info.cfile, crdev->page_info.cfname, false); |
542 | 0 | if (ecode >= 0) { |
543 | 0 | crdev->page_info.cfile = NULL; |
544 | 0 | ecode = crdev->page_info.io_procs->fclose(crdev->page_info.bfile, crdev->page_info.bfname, false); |
545 | 0 | } |
546 | 0 | if (ecode < 0) { |
547 | 0 | code = ecode; |
548 | 0 | goto out; |
549 | 0 | } |
550 | 0 | crdev->page_info.bfile = NULL; |
551 | |
|
552 | 0 | out: |
553 | 0 | pdev->space_params.banding_type = save_banding_type; |
554 | 0 | return code; |
555 | 0 | } |
556 | | |
557 | | /* |
558 | | * Print selected pages from the list to on the selected device. The |
559 | | * saved_pages_list is NOT modified, allowing for reprint / recovery |
560 | | * print. Each saved_page is printed on a separate page (unlike the |
561 | | * gdev_prn_render_pages above which prints several saved_pages on |
562 | | * a single "master" page, performing imposition). |
563 | | * |
564 | | * This is primarily intended to allow printing in non-standard order |
565 | | * (reverse, odd, even) or producing collated copies for a job. |
566 | | * |
567 | | * On success return the number of bytes consumed or error code < 0. |
568 | | * The printed_count will contain the number of pages printed. |
569 | | * |
570 | | * ------------------------------------------------------------------- |
571 | | * |
572 | | * The param string may begin with whitespace. The string is parsed |
573 | | * and the selected pages are printed. There may be any number of ranges |
574 | | * and or keywords separated by whitespace and/or comma ','. |
575 | | * |
576 | | * NB: The pdev printer device's PageCount is updated to reflect the |
577 | | * total number of pages produced (per the spec for this parameter) |
578 | | * since we may be producing multiple collated copies. |
579 | | * Also the list PageCount is updated after printing since |
580 | | * there may be a subsequent 'print' action. |
581 | | * keywords: |
582 | | * copies # Set the number of copies for subsequent printing actions |
583 | | * "copies 1" resets to a single copy |
584 | | * normal All pages are printed in normal order |
585 | | * reverse All pages are printed in reverse order |
586 | | * The following two options may be useful for duplexing. |
587 | | * odd All odd pages are printed, e.g. 1, 3, 5, ... |
588 | | * even All even pages are printed, e.g. 2, 4, 6, ... |
589 | | * NB: an extra blank page will be printed if the list |
590 | | * has an odd number of pages. |
591 | | * even0pad All even pages, but no extra blank page if there are |
592 | | * an odd number of pages on the list. |
593 | | * range syntax: |
594 | | * range range multiple ranges are separated by commas ',' |
595 | | * and/or whitespace. |
596 | | * # a specific page number is a valid range |
597 | | * |
598 | | * inclusive ranges below can have whitespace before |
599 | | * or after the dash '-'. |
600 | | * #-# a range consisting of all pages from the first |
601 | | * page # up to (and including) the second page #. |
602 | | * #-* all pages from # up through the last page |
603 | | * "1-*" is equivalent to "normal" |
604 | | * *-# all pages from the last up through # page. |
605 | | * "reverse" is equivalent to "*-1" |
606 | | */ |
607 | | int |
608 | | gx_saved_pages_list_print(gx_device_printer *pdev, gx_saved_pages_list *list, |
609 | | byte *param, int param_size, int *printed_count) |
610 | 0 | { |
611 | 0 | byte *param_scan = NULL; |
612 | 0 | int param_left; |
613 | 0 | int start_page = 0; /* 0 means start_page unknown */ |
614 | 0 | int end_page = 0; /* < 0 means waiting for the end of a # - # range */ |
615 | | /* i.e, a '-' was scanned. 0 means unknown */ |
616 | 0 | int tmp_num; /* during token scanning loop */ |
617 | 0 | int code = 0, endcode = 0; |
618 | 0 | byte *token; |
619 | 0 | int copy, token_size; |
620 | 0 | gx_device_clist_reader *crdev = (gx_device_clist_reader *)pdev; |
621 | | /* the following are used so we can go back to the original state */ |
622 | 0 | bool save_bg_print = false; /* arbitrary, silence warning */ |
623 | 0 | bool save_bandfile_open_close = false; /* arbitrary, silence warning */ |
624 | 0 | gx_saved_page saved_page; |
625 | 0 | clist_file_ptr saved_files[2]; |
626 | | |
627 | | /* save the current (empty) page while we print */ |
628 | 0 | if ((code = do_page_save(pdev, &saved_page, saved_files)) < 0) { |
629 | 0 | emprintf(pdev->memory, "gx_saved_pages_list_print: Error getting device params\n"); |
630 | 0 | goto out; |
631 | 0 | } |
632 | | |
633 | | /* save_page leaves the clist in writer mode, so prepare for reading clist */ |
634 | | /* files. When we are done with printing, we'll go back to write mode. */ |
635 | 0 | if ((code = clist_close_writer_and_init_reader((gx_device_clist *)pdev)) < 0) |
636 | 0 | goto out; |
637 | | |
638 | | /* While printing, disable the saved_pages mode and bg_print */ |
639 | 0 | pdev->saved_pages_list = NULL; |
640 | 0 | save_bg_print = pdev->bg_print_requested; |
641 | | |
642 | | /* Inhibits modifying the clist at end of output_page */ |
643 | 0 | save_bandfile_open_close = crdev->do_not_open_or_close_bandfiles; |
644 | 0 | crdev->do_not_open_or_close_bandfiles = true; |
645 | |
|
646 | 0 | pdev->PageCount = list->PageCount; /* adjust to value last printed */ |
647 | | |
648 | | /* loop producing the number of copies */ |
649 | | /* Note: list->collated_copies may change if 'copies' param follows the 'print' */ |
650 | 0 | for (copy = 1; copy <= list->collated_copies; copy++) { |
651 | 0 | int page_skip = 0; |
652 | 0 | bool do_blank_page_pad; |
653 | 0 | int page; |
654 | | |
655 | | /* Set to start of 'print' params to do collated copies */ |
656 | 0 | param_scan = param; |
657 | 0 | param_left = param_size; |
658 | 0 | while ((token = param_parse_token(param_scan, param_left, &token_size)) != NULL) { |
659 | 0 | saved_pages_key_enum key; |
660 | |
|
661 | 0 | page = 0; |
662 | 0 | do_blank_page_pad = false; /* only set for EVEN */ |
663 | 0 | key = param_find_key(token, token_size); |
664 | 0 | switch (key) { |
665 | 0 | case PARAM_DASH: |
666 | 0 | if (start_page == 0) { |
667 | 0 | emprintf(pdev->memory, "gx_saved_pages_list_print: '-' unexpected\n"); |
668 | 0 | code = gs_error_typecheck; |
669 | 0 | goto out; |
670 | 0 | } |
671 | 0 | end_page = -1; /* the next number will end a range */ |
672 | 0 | break; |
673 | | |
674 | 0 | case PARAM_STAR: |
675 | 0 | page = list->count; /* last page */ |
676 | 0 | case PARAM_NUMBER: |
677 | 0 | if (page == 0) { |
678 | 0 | if (sscanf((const char *)token, "%d", &page) != 1) { |
679 | 0 | emprintf1(pdev->memory, "gx_saved_pages_list_print: Number format error '%s'\n", token); |
680 | 0 | code = gs_error_typecheck; |
681 | 0 | goto out; |
682 | 0 | } |
683 | 0 | } |
684 | 0 | if (start_page == 0) { |
685 | 0 | start_page = page; /* first number seen */ |
686 | 0 | } else { |
687 | | /* a second number was seen after the start_page was set */ |
688 | 0 | if (end_page < 0) { |
689 | 0 | end_page = page; /* end of a '# - #' range */ |
690 | 0 | page_skip = (end_page >= start_page) ? 1 : -1; |
691 | 0 | } else { |
692 | | /* 'page' was NOT part of a range after printing 'page' will start a new range */ |
693 | 0 | end_page = start_page; /* single page */ |
694 | 0 | page_skip = 1; |
695 | 0 | } |
696 | 0 | } |
697 | 0 | break; |
698 | | |
699 | 0 | case PARAM_COPIES: /* copies requires a number next */ |
700 | | /* Move to past 'copies' token */ |
701 | 0 | param_left -= token - param_scan + token_size; |
702 | 0 | param_scan = token + token_size; |
703 | |
|
704 | 0 | if ((token = param_parse_token(param_scan, param_left, &token_size)) == NULL || |
705 | 0 | param_find_key(token, token_size) != PARAM_NUMBER) { |
706 | 0 | emprintf(pdev->memory, "gx_saved_pages_list_print: copies not followed by number.\n"); |
707 | 0 | code = gs_error_typecheck; |
708 | 0 | goto out; |
709 | 0 | } |
710 | 0 | if (sscanf((const char *)token, "%d", &tmp_num) != 1) { |
711 | 0 | emprintf1(pdev->memory, "gx_saved_pages_list_print: Number format error '%s'\n", token); |
712 | 0 | code = gs_error_typecheck; |
713 | 0 | goto out; |
714 | 0 | } |
715 | 0 | list->collated_copies = tmp_num; /* save it for our loop */ |
716 | 0 | break; |
717 | | |
718 | 0 | case PARAM_NORMAL: /* sets both start and end */ |
719 | 0 | start_page = 1; |
720 | 0 | end_page = list->count; |
721 | 0 | page_skip = 1; |
722 | 0 | break ; |
723 | | |
724 | 0 | case PARAM_REVERSE: /* sets both start and end */ |
725 | 0 | start_page = list->count; |
726 | 0 | end_page = 1; |
727 | 0 | page_skip = -1; |
728 | 0 | break; |
729 | | |
730 | 0 | case PARAM_EVEN: /* sets both start and end */ |
731 | 0 | do_blank_page_pad = (list->count & 1) != 0; /* pad if odd */ |
732 | 0 | case PARAM_EVEN0PAD: /* sets both start and end */ |
733 | 0 | start_page = 2; |
734 | 0 | end_page = list->count; |
735 | 0 | page_skip = 2; |
736 | 0 | break ; |
737 | | |
738 | 0 | case PARAM_ODD: /* sets both start and end */ |
739 | 0 | start_page = 1; |
740 | 0 | end_page = list->count; |
741 | 0 | page_skip = 2; |
742 | 0 | break ; |
743 | | |
744 | 0 | case PARAM_UNKNOWN: |
745 | 0 | case PARAM_BEGIN: |
746 | 0 | case PARAM_END: |
747 | 0 | case PARAM_FLUSH: |
748 | 0 | case PARAM_PRINT: |
749 | 0 | token_size = 0; /* non-print range token seen */ |
750 | 0 | } |
751 | 0 | if (end_page > 0) { |
752 | | /* Here we have a range to print since start and end are known */ |
753 | 0 | int curr_page = start_page; |
754 | 0 | gx_saved_pages_list_element *curr_elem = NULL; |
755 | | |
756 | | /* get the start_page saved_page */ |
757 | 0 | if (start_page <= list->count) { |
758 | 0 | for (curr_elem = list->head; curr_elem->sequence_number != start_page; |
759 | 0 | curr_elem = curr_elem->next) { |
760 | 0 | if (curr_elem->next == NULL) { |
761 | 0 | emprintf1(pdev->memory, "gx_saved_pages_list_print: page %d not found.\n", start_page); |
762 | 0 | code = gs_error_rangecheck;; |
763 | 0 | goto out; |
764 | 0 | } |
765 | 0 | } |
766 | 0 | } |
767 | | |
768 | 0 | for ( ; curr_elem != NULL; ) { |
769 | | |
770 | | /* print the saved page from the current curr_elem */ |
771 | |
|
772 | 0 | if (gs_debug_c(':')) |
773 | 0 | dmprintf1(pdev->memory, "Printing page %d\n", curr_page); |
774 | 0 | if ((code = gx_output_saved_page(pdev, curr_elem->page)) < 0) |
775 | 0 | goto out; |
776 | | |
777 | 0 | curr_page += page_skip; |
778 | 0 | if (page_skip >= 0) { |
779 | 0 | if (curr_page > end_page) |
780 | 0 | break; |
781 | 0 | curr_elem = curr_elem->next; |
782 | 0 | if (page_skip > 1) |
783 | 0 | curr_elem = curr_elem->next; |
784 | 0 | } else { |
785 | | /* reverse print order */ |
786 | 0 | if (curr_page < end_page) |
787 | 0 | break; |
788 | 0 | curr_elem = curr_elem->prev; |
789 | | /* Below is not needed since we never print reverse even/odd */ |
790 | 0 | if (page_skip < -1) /* lgtm [cpp/constant-comparison] */ |
791 | 0 | curr_elem = curr_elem->prev; |
792 | 0 | } |
793 | 0 | if (curr_elem == NULL) { |
794 | 0 | emprintf1(pdev->memory, "gx_saved_pages_list_print: page %d not found.\n", curr_page); |
795 | 0 | code = gs_error_rangecheck;; |
796 | 0 | goto out; |
797 | 0 | } |
798 | 0 | } |
799 | | |
800 | | /* If we were printing EVEN, we may need to spit out a blank 'pad' page */ |
801 | 0 | if (do_blank_page_pad) { |
802 | | /* print the empty page we had upon entry */ |
803 | | /* FIXME: Note that the page size may not match the last odd page */ |
804 | 0 | if ((code = gx_output_saved_page(pdev, &saved_page)) < 0) |
805 | 0 | goto out; |
806 | 0 | } |
807 | | |
808 | | /* After printing, reset to handle next page range */ |
809 | 0 | start_page = (start_page == end_page) ? page : 0; /* if single page, set start_page */ |
810 | | /* from the number scanned above */ |
811 | 0 | end_page = 0; |
812 | 0 | } |
813 | 0 | if (token_size == 0) |
814 | 0 | break; /* finished with print ranges */ |
815 | | |
816 | | /* Move to next token */ |
817 | 0 | param_left -= token - param_scan + token_size; |
818 | 0 | param_scan = token + token_size; |
819 | 0 | } |
820 | 0 | } |
821 | 0 | out: |
822 | | /* restore the device parameters saved upon entry */ |
823 | 0 | *printed_count = pdev->PageCount - list->PageCount; |
824 | 0 | list->PageCount = pdev->PageCount; /* retain for subsequent print action */ |
825 | 0 | pdev->saved_pages_list = list; |
826 | 0 | pdev->bg_print_requested = save_bg_print; |
827 | 0 | crdev->do_not_open_or_close_bandfiles = save_bandfile_open_close; |
828 | | |
829 | | /* load must be after we've set saved_pages_list which forces clist mode. */ |
830 | 0 | do_page_load(pdev, &saved_page, saved_files); |
831 | | |
832 | | /* Finally, do the finish page which will reset the clist to empty and write mode */ |
833 | 0 | endcode = clist_finish_page((gx_device *)pdev, true); |
834 | 0 | return code < 0 ? code : endcode < 0 ? endcode : param_scan - param; |
835 | 0 | } |
836 | | |
837 | | /* |
838 | | * Caller should make sure that this device supports saved_pages: |
839 | | * dev_proc(dev, dev_spec_op)(dev, gxdso_supports_saved_pages, NULL, 0) == 1 |
840 | | * |
841 | | * Returns < 0 if error, 1 if erasepage needed, 0 if no action needed. |
842 | | */ |
843 | | int |
844 | | gx_saved_pages_param_process(gx_device_printer *pdev, byte *param, int param_size) |
845 | 0 | { |
846 | 0 | byte *param_scan = param; |
847 | 0 | int param_left = param_size; |
848 | 0 | byte *token; |
849 | 0 | int token_size, code, printed_count, collated_copies = 1; |
850 | 0 | int tmp_num; /* during token scanning loop */ |
851 | 0 | int erasepage_needed = 0; |
852 | |
|
853 | 0 | while (pdev->child) |
854 | 0 | pdev = (gx_device_printer *)pdev->child; |
855 | |
|
856 | 0 | while ((token = param_parse_token(param_scan, param_left, &token_size)) != NULL) { |
857 | |
|
858 | 0 | switch (param_find_key(token, token_size)) { |
859 | 0 | case PARAM_BEGIN: |
860 | 0 | if (pdev->saved_pages_list == NULL) { |
861 | 0 | if ((pdev->saved_pages_list = gx_saved_pages_list_new(pdev)) == NULL) |
862 | 0 | return_error(gs_error_VMerror); |
863 | 0 | pdev->finalize = gdev_prn_finalize; /* set to make sure the list gets freed */ |
864 | | |
865 | | /* We need to change to clist mode. Always uses clist when saving pages */ |
866 | 0 | pdev->saved_pages_list->save_banding_type = pdev->space_params.banding_type; |
867 | 0 | pdev->space_params.banding_type = BandingAlways; |
868 | 0 | if ((code = gdev_prn_reallocate_memory((gx_device *)pdev, &pdev->space_params, pdev->width, pdev->height)) < 0) |
869 | 0 | return code; |
870 | 0 | erasepage_needed |= 1; |
871 | 0 | } |
872 | 0 | break; |
873 | | |
874 | 0 | case PARAM_END: |
875 | 0 | if (pdev->saved_pages_list != NULL) { |
876 | | /* restore to what was set before the "begin" */ |
877 | 0 | pdev->space_params.banding_type = pdev->saved_pages_list->save_banding_type; |
878 | 0 | gx_saved_pages_list_free(pdev->saved_pages_list); |
879 | 0 | pdev->saved_pages_list = NULL; |
880 | | /* We may need to change from clist mode since we forced clist when saving pages */ |
881 | 0 | code = gdev_prn_reallocate_memory((gx_device *)pdev, &pdev->space_params, pdev->width, pdev->height); |
882 | 0 | if (code < 0) |
883 | 0 | return code; |
884 | 0 | erasepage_needed |= 1; /* make sure next page is erased */ |
885 | 0 | } |
886 | 0 | break; |
887 | | |
888 | 0 | case PARAM_FLUSH: |
889 | 0 | if (pdev->saved_pages_list != NULL) { |
890 | | /* Save the collated copy count so the list we return will have it */ |
891 | 0 | collated_copies = pdev->saved_pages_list->collated_copies; |
892 | 0 | gx_saved_pages_list_free(pdev->saved_pages_list); |
893 | 0 | } |
894 | | /* Always return with an empty list, even if we weren't saving previously */ |
895 | 0 | if ((pdev->saved_pages_list = gx_saved_pages_list_new(pdev)) == NULL) |
896 | 0 | return_error(gs_error_VMerror); |
897 | 0 | pdev->finalize = gdev_prn_finalize; /* set to make sure the list gets freed */ |
898 | | /* restore the original count */ |
899 | 0 | pdev->saved_pages_list->collated_copies = collated_copies; |
900 | 0 | break; |
901 | | |
902 | 0 | case PARAM_COPIES: /* copies requires a number next */ |
903 | | /* make sure that we have a list */ |
904 | 0 | if (pdev->saved_pages_list == NULL) { |
905 | 0 | return_error(gs_error_rangecheck); /* copies not allowed before a 'begin' */ |
906 | 0 | } |
907 | | /* Move to past 'copies' token */ |
908 | 0 | param_left -= token - param_scan + token_size; |
909 | 0 | param_scan = token + token_size; |
910 | |
|
911 | 0 | if ((token = param_parse_token(param_scan, param_left, &token_size)) == NULL || |
912 | 0 | param_find_key(token, token_size) != PARAM_NUMBER) { |
913 | 0 | emprintf(pdev->memory, "gx_saved_pages_param_process: copies not followed by number.\n"); |
914 | 0 | return_error(gs_error_typecheck); |
915 | 0 | } |
916 | 0 | if (sscanf((const char *)token, "%d", &tmp_num) != 1) { |
917 | 0 | emprintf1(pdev->memory, "gx_saved_pages_list_print: Number format error '%s'\n", token); |
918 | 0 | code = gs_error_typecheck; |
919 | 0 | return code; |
920 | 0 | } |
921 | 0 | pdev->saved_pages_list->collated_copies = tmp_num; /* save it for our loop */ |
922 | 0 | break; |
923 | | |
924 | 0 | case PARAM_PRINT: |
925 | | /* Move to past 'print' token */ |
926 | 0 | param_left -= token - param_scan + token_size; |
927 | 0 | param_scan = token + token_size; |
928 | |
|
929 | 0 | code = param_left; /* in case list is NULL, skip rest of string */ |
930 | 0 | if (pdev->saved_pages_list != NULL) { |
931 | 0 | if ((code = gx_saved_pages_list_print(pdev, pdev->saved_pages_list, |
932 | 0 | param_scan, param_left, &printed_count)) < 0) |
933 | 0 | return code; |
934 | 0 | erasepage_needed |= 1; /* make sure next page is erased */ |
935 | 0 | } |
936 | | /* adjust for all of the print parameters */ |
937 | 0 | token_size += code; |
938 | 0 | break; |
939 | | |
940 | | /* We are expecting an action keyword, so other keywords and tokens */ |
941 | | /* are not valid here (mostly the 'print' parameters). */ |
942 | 0 | default: |
943 | 0 | { |
944 | 0 | byte *bad_token = gs_alloc_string(pdev->memory, token_size+1, "saved_pages_param_process"); |
945 | 0 | byte *param_string = gs_alloc_string(pdev->memory, param_size+1, "saved_pages_param_process"); |
946 | 0 | if (bad_token != NULL && param_string != NULL) { |
947 | 0 | memcpy(bad_token, token, token_size); |
948 | 0 | bad_token[token_size] = 0; /* terminate string */ |
949 | 0 | memcpy(param_string, param, param_size); |
950 | 0 | param_string[param_size] = 0; /* terminate string */ |
951 | 0 | emprintf2(pdev->memory, "*** Invalid saved-pages token '%s'\n *** in param string '%s'\n", |
952 | 0 | bad_token, param_string); |
953 | 0 | gs_free_string(pdev->memory, bad_token, token_size+1, "saved_pages_param_process"); |
954 | 0 | gs_free_string(pdev->memory, param_string, param_size+1, "saved_pages_param_process"); |
955 | 0 | } |
956 | 0 | } |
957 | 0 | } |
958 | | /* Move to next token */ |
959 | 0 | param_left -= token - param_scan + token_size; |
960 | 0 | param_scan = token + token_size; |
961 | |
|
962 | 0 | } |
963 | 0 | return erasepage_needed; |
964 | 0 | } |