summaryrefslogtreecommitdiff
path: root/xps
diff options
context:
space:
mode:
authorMichael Vrhel <michael.vrhel@artifex.com>2020-08-26 16:53:36 -0700
committerMichael Vrhel <michael.vrhel@artifex.com>2020-09-22 10:13:31 -0700
commit9bfaeeace268f6a59f325e12efab9fb8273f64e0 (patch)
tree4cb7bdb6ee283bcef465e2918ff00d68db8d9021 /xps
parentc4e79952b42ebccb669063e053e3d7ce0f88cc22 (diff)
downloadghostpdl-9bfaeeace268f6a59f325e12efab9fb8273f64e0.tar.gz
XPS interpreter: Have interpreter handle page range processing
This has the obvious benefit that the interpreter will skip processing pages except those that lie in the FirstPage LastPage range. If the PageList is used, the XPS interpreter will create a new list of linked pages to process. The XPS interpreter handles all the PageList cases currently implemented by the PDF interpreter including even and odd. In addition, the XPS interpreter will handle backward indexing (e.g. 100-1), as well as starting from last page to another page (e.g. -2 which means from last page to second page), and page repeats (e.g. 1,2,1,2,1,2 or 1-3,3-1 or 1-,-1 which is do page 1 to end and end to page 1) Also, setting -dFirstPage=4 -dLastPage=1 will create pages 4,3,2,1
Diffstat (limited to 'xps')
-rw-r--r--xps/ghostxps.h12
-rw-r--r--xps/xps.mak2
-rw-r--r--xps/xpsdoc.c31
-rw-r--r--xps/xpstop.c67
-rw-r--r--xps/xpszip.c205
5 files changed, 314 insertions, 3 deletions
diff --git a/xps/ghostxps.h b/xps/ghostxps.h
index 19ffb236f..cf029db4d 100644
--- a/xps/ghostxps.h
+++ b/xps/ghostxps.h
@@ -177,6 +177,7 @@ void xps_free_part(xps_context_t *ctx, xps_part_t *part);
typedef struct xps_document_s xps_document_t;
typedef struct xps_page_s xps_page_t;
+typedef struct xps_page_range_s xps_page_range_t;
struct xps_document_s
{
@@ -192,6 +193,15 @@ struct xps_page_s
xps_page_t *next;
};
+struct xps_page_range_s
+{
+ int first;
+ int last;
+ int reverse;
+ int current;
+ char *page_list;
+};
+
int xps_parse_metadata(xps_context_t *ctx, xps_part_t *part);
void xps_free_fixed_pages(xps_context_t *ctx);
void xps_free_fixed_documents(xps_context_t *ctx);
@@ -410,6 +420,8 @@ struct xps_context_s
xps_page_t *first_page; /* first page of document */
xps_page_t *last_page; /* last page of document */
+ xps_page_range_t *page_range; /* interpreter-based page range handling */
+
char *base_uri; /* base uri for parsing XML and resolving relative paths */
char *part_uri; /* part uri for parsing metadata relations */
diff --git a/xps/xps.mak b/xps/xps.mak
index 105e2d640..c1b4d0a89 100644
--- a/xps/xps.mak
+++ b/xps/xps.mak
@@ -137,7 +137,7 @@ $(PLOBJ)xpsimpl.$(OBJ): $(XPSGEN)xpsimpl.c \
$(MAKEDIRS)
$(XPSCCC) $(XPSGEN)xpsimpl.c $(XPSO_)xpsimpl.$(OBJ)
-$(XPS_TOP_OBJ): $(XPSSRC)xpstop.c $(plmain_h) $(pltop_h) $(XPSINCLUDES) $(GLOBJ)gconfig.$(OBJ) \
+$(XPS_TOP_OBJ): $(XPSSRC)xpstop.c $(plmain_h) $(pltop_h) $(gsparam_h) $(XPSINCLUDES) $(GLOBJ)gconfig.$(OBJ) \
$(pconfig_h) $(XPS_MAK) $(MAKEDIRS)
$(XPSCCC) $(XPSSRC)xpstop.c $(XPSO_)xpstop.$(OBJ)
diff --git a/xps/xpsdoc.c b/xps/xpsdoc.c
index 17fce9fc1..97445ec2f 100644
--- a/xps/xpsdoc.c
+++ b/xps/xpsdoc.c
@@ -134,6 +134,24 @@ xps_add_fixed_page(xps_context_t *ctx, char *name, int width, int height)
if (!strcmp(page->name, name))
return;
+ if (ctx->page_range && !ctx->page_range->page_list)
+ {
+ ctx->page_range->current++;
+
+ if (ctx->page_range->reverse)
+ {
+ if (ctx->page_range->current < ctx->page_range->last ||
+ ctx->page_range->current > ctx->page_range->first)
+ return;
+ }
+ else
+ {
+ if ((ctx->page_range->first != 0 && ctx->page_range->current < ctx->page_range->first) ||
+ (ctx->page_range->last != 0 && ctx->page_range->current > ctx->page_range->last))
+ return;
+ }
+ }
+
if_debug1m('|', ctx->memory, "doc: adding page %s\n", name);
page = xps_alloc(ctx, sizeof(xps_page_t));
@@ -153,8 +171,17 @@ xps_add_fixed_page(xps_context_t *ctx, char *name, int width, int height)
}
else
{
- ctx->last_page->next = page;
- ctx->last_page = page;
+ /* FirstPage < LastPage? */
+ if (ctx->page_range && ctx->page_range->reverse)
+ {
+ page->next = ctx->first_page;
+ ctx->first_page = page;
+ }
+ else
+ {
+ ctx->last_page->next = page;
+ ctx->last_page = page;
+ }
}
}
diff --git a/xps/xpstop.c b/xps/xpstop.c
index 6717da985..424ca12fb 100644
--- a/xps/xpstop.c
+++ b/xps/xpstop.c
@@ -27,6 +27,7 @@
#include "gxdevice.h" /* so we can include gxht.h below */
#include "gxht.h" /* gsht1.h is incomplete, we need storage size of gs_halftone */
#include "gsht1.h"
+#include "gsparam.h"
#include <assert.h>
@@ -197,6 +198,9 @@ xps_impl_init_job(pl_interp_implementation_t *impl,
xps_context_t *ctx = instance->ctx;
gs_c_param_list list;
int code;
+ bool disable_page_handler = false;
+ int true_val = 1;
+ gs_memory_t* mem = ctx->memory;
if (gs_debug_c('|'))
xps_zip_trace = 1;
@@ -237,6 +241,61 @@ xps_impl_init_job(pl_interp_implementation_t *impl,
gs_setscanconverter(ctx->pgs, pl_main_get_scanconverter(ctx->memory));
+ /* Disable the page handler as the XPS interpreter will handle page range.
+ List takes precedent over firstpage lastpage */
+ if (pdevice->PageList != NULL && pdevice->PageHandlerPushed)
+ {
+ ctx->page_range = xps_alloc(ctx, sizeof(xps_page_range_t));
+ if (!ctx->page_range)
+ {
+ return gs_rethrow(gs_error_VMerror, "out of memory: page_range struct");
+ }
+
+ ctx->page_range->page_list = xps_strdup(ctx, pdevice->PageList->Pages);
+ if (!ctx->page_range->page_list)
+ {
+ return gs_rethrow(gs_error_VMerror, "out of memory: page_list");
+ }
+ disable_page_handler = true;
+ }
+ else if ((pdevice->FirstPage > 0 || pdevice->LastPage > 0) &&
+ pdevice->PageHandlerPushed)
+ {
+ disable_page_handler = true;
+
+ ctx->page_range = xps_alloc(ctx, sizeof(xps_page_range_t));
+ if (!ctx->page_range)
+ {
+ return gs_throw(gs_error_VMerror, "out of memory: page_range struct");
+ }
+ ctx->page_range->first = pdevice->FirstPage;
+ ctx->page_range->last = pdevice->LastPage;
+ ctx->page_range->current = 0;
+ ctx->page_range->page_list = NULL;
+
+ if (ctx->page_range->first != 0 &&
+ ctx->page_range->last != 0 &&
+ ctx->page_range->first > ctx->page_range->last)
+ ctx->page_range->reverse = true;
+ else
+ ctx->page_range->reverse = false;
+ }
+
+ if (disable_page_handler)
+ {
+ gs_c_param_list_write(&list, mem);
+ code = param_write_bool((gs_param_list*)&list, "DisablePageHandler", &(true_val));
+ if (code >= 0)
+ {
+ gs_c_param_list_read(&list);
+ code = gs_putdeviceparams(pdevice, (gs_param_list*)&list);
+ gs_c_param_list_release(&list);
+ if (code < 0) {
+ return gs_rethrow(code, "cannot set device parameters");
+ }
+ }
+ }
+
/* gsave and grestore (among other places) assume that */
/* there are at least 2 gstates on the graphics stack. */
/* Ensure that now. */
@@ -413,6 +472,14 @@ xps_impl_dnit_job(pl_interp_implementation_t *impl)
xps_hash_free(ctx, ctx->font_table, xps_free_key_func, xps_free_font_func);
xps_hash_free(ctx, ctx->colorspace_table, xps_free_key_func, xps_free_hashed_colorspace);
+ if (ctx->page_range)
+ {
+ if (ctx->page_range->page_list)
+ xps_free(ctx, ctx->page_range->page_list);
+ xps_free(ctx, ctx->page_range);
+ ctx->page_range = NULL;
+ }
+
xps_free_fixed_pages(ctx);
xps_free_fixed_documents(ctx);
diff --git a/xps/xpszip.c b/xps/xpszip.c
index 1c3843567..d00678794 100644
--- a/xps/xpszip.c
+++ b/xps/xpszip.c
@@ -565,6 +565,200 @@ xps_read_and_process_page_part(xps_context_t *ctx, char *name)
return gs_okay;
}
+/* XPS page reordering based upon Device PageList setting */
+static int
+xps_reorder_add_page(xps_context_t* ctx, xps_page_t ***page_ptr, xps_page_t* page_to_add)
+{
+ xps_page_t* new_page;
+
+ new_page = xps_alloc(ctx, sizeof(xps_page_t));
+ if (!new_page)
+ {
+ return gs_throw(gs_error_VMerror, "out of memory: xps_reorder_add_page\n");
+ }
+
+ new_page->name = xps_strdup(ctx, page_to_add->name);
+ if (!new_page->name)
+ {
+ return gs_throw(gs_error_VMerror, "out of memory: xps_reorder_add_page\n");
+ }
+ new_page->height = page_to_add->height;
+ new_page->width = page_to_add->width;
+ new_page->next = NULL;
+
+ **page_ptr = new_page;
+ *page_ptr = &(new_page->next);
+
+ return 0;
+}
+
+static char*
+xps_reorder_get_range(xps_context_t *ctx, char *page_list, int *start, int *end, int num_pages)
+{
+ int comma, dash, len;
+
+ len = strlen(page_list);
+ comma = strcspn(page_list, ",");
+ dash = strcspn(page_list, "-");
+
+ if (dash < comma)
+ {
+ /* Dash at start */
+ if (dash == 0)
+ {
+ *start = num_pages;
+ *end = atoi(&(page_list[dash + 1]));
+ }
+ else
+ {
+ *start = atoi(page_list);
+
+ /* Dash at end */
+ if (page_list[dash + 1] == 0 || page_list[dash + 1] == ',')
+ {
+ *end = num_pages;
+ }
+ else
+ {
+ *end = atoi(&(page_list[dash + 1]));
+ }
+ }
+ }
+ else
+ {
+ *start = atoi(page_list);
+ *end = *start;
+ }
+ return comma == len ? page_list + comma : page_list + comma + 1;
+}
+
+static int
+xps_reorder_pages(xps_context_t *ctx)
+{
+ char *page_list = ctx->page_range->page_list;
+ char *str;
+ xps_page_t **page_ptr_array, *page = ctx->first_page;
+ int count = 0, k;
+ int code;
+ int start;
+ int end;
+ xps_page_t* first_page = NULL;
+ xps_page_t* last_page;
+ xps_page_t** page_tail = &first_page;
+
+ if (page == NULL)
+ return 0;
+
+ while (page != NULL)
+ {
+ count++;
+ page = page->next;
+ }
+
+ /* Create an array of pointers to the current pages */
+ page_ptr_array = xps_alloc(ctx, sizeof(xps_page_t*) * count);
+ if (page_ptr_array == NULL)
+ return gs_throw(gs_error_VMerror, "out of memory: xps_reorder_pages\n");
+
+ page = ctx->first_page;
+ for (k = 0; k < count; k++)
+ {
+ page_ptr_array[k] = page;
+ page = page->next;
+ }
+
+ if (strcmp(page_list, "even") == 0)
+ {
+ for (k = 1; k < count; k += 2)
+ {
+ code = xps_reorder_add_page(ctx, &page_tail, page_ptr_array[k]);
+ if (code < 0)
+ return code;
+ }
+ }
+ else if (strcmp(page_list, "odd") == 0)
+ {
+ for (k = 0; k < count; k += 2)
+ {
+ code = xps_reorder_add_page(ctx, &page_tail, page_ptr_array[k]);
+ if (code < 0)
+ return code;
+ }
+ }
+ else
+ {
+ /* Requirements. All characters must be 0 to 9 or - and ,
+ No ,, or -- */
+ str = page_list;
+ do
+ {
+ if (*str != ',' && *str != '-' && (*str < 0x30 || *str > 0x39))
+ return gs_throw(gs_error_typecheck, "Bad page list: xps_reorder_pages\n");
+
+ if ((*str == ',' && *(str + 1) == ',') || (*str == '-' && *(str + 1) == '-'))
+ return gs_throw(gs_error_typecheck, "Bad page list: xps_reorder_pages\n");
+ }
+ while (*(++str));
+
+ str = page_list;
+ do
+ {
+ /* Process each comma separated item. */
+ str = xps_reorder_get_range(ctx, str, &start, &end, count);
+
+ /* Threshold page range */
+ if (start > count)
+ start = count;
+
+ if (end > count)
+ end = count;
+
+ /* Add page(s) */
+ if (start == end)
+ {
+ code = xps_reorder_add_page(ctx, &page_tail, page_ptr_array[start - 1]);
+ if (code < 0)
+ return code;
+ }
+ else if (start < end)
+ {
+ for (k = start - 1; k < end; k++)
+ {
+ code = xps_reorder_add_page(ctx, &page_tail, page_ptr_array[k]);
+ if (code < 0)
+ return code;
+ }
+ }
+ else
+ {
+ for (k = start; k >= end; k--)
+ {
+ code = xps_reorder_add_page(ctx, &page_tail, page_ptr_array[k - 1]);
+ if (code < 0)
+ return code;
+ }
+ }
+ }
+ while (*str);
+ }
+
+ /* Replace the pages. */
+ if (first_page != NULL)
+ {
+ /* Set to the last page not its next pointer (Thanks to Robin Watts) */
+ last_page = (xps_page_t*)(((char*)page_tail) - offsetof(xps_page_t, next));
+
+ xps_free_fixed_pages(ctx);
+ xps_free(ctx, page_ptr_array);
+ ctx->first_page = first_page;
+ ctx->last_page = last_page;
+ }
+ else
+ return gs_throw(gs_error_rangecheck, "Bad page list: xps_reorder_pages\n");
+
+ return 0;
+}
+
/*
* Called by xpstop.c
*/
@@ -700,6 +894,17 @@ xps_process_file(xps_context_t *ctx, const char *filename)
}
}
+ /* If we have a page list, adjust pages now */
+ if (ctx->page_range && ctx->page_range->page_list)
+ {
+ code = xps_reorder_pages(ctx);
+ if (code)
+ {
+ code = gs_rethrow(code, "invalid page range setting");
+ goto cleanup;
+ }
+ }
+
for (page = ctx->first_page; page; page = page->next)
{
code = xps_read_and_process_page_part(ctx, page->name);