jobextra/libxslt/0001-Make-generate-id-deter...

182 lines
5.3 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Veillard <veillard@redhat.com>
Date: Sun, 29 Oct 2017 01:04:54 +0200
Subject: [PATCH] Make generate-id deterministic
Origin: upstream, https://bugzilla.gnome.org/attachment.cgi?id=306475
Bug: https://bugzilla.gnome.org/show_bug.cgi?id=751621
Bug-Debian: https://bugs.debian.org/823857
---
libxslt/functions.c | 91 ++++++++++++++++++++++++++++++++++++++++-
libxslt/functions.h | 7 ++++
libxslt/transform.c | 8 ++++
libxslt/xsltInternals.h | 2 +
4 files changed, 107 insertions(+), 1 deletion(-)
diff --git a/libxslt/functions.c b/libxslt/functions.c
index ed2b002362dc..9c4408b325bd 100644
--- a/libxslt/functions.c
+++ b/libxslt/functions.c
@@ -662,6 +662,63 @@ xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs)
xmlXPathFreeObject(decimalObj);
}
+/**
+ * xsltCleanupIds:
+ * @ctxt: the transformation context
+ * @root: the root of the resulting document
+ *
+ * This clean up ids which may have been saved in Element contents
+ * by xsltGenerateIdFunction() to provide stable IDs on elements.
+ *
+ * Returns the number of items cleaned or -1 in case of error
+ */
+int
+xsltCleanupIds(xsltTransformContextPtr ctxt, xmlNodePtr root) {
+ xmlNodePtr cur;
+ int count = 0;
+
+ if ((ctxt == NULL) || (root == NULL))
+ return(-1);
+ if (root->type != XML_ELEMENT_NODE)
+ return(-1);
+
+ cur = root;
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE) {
+ if (cur->content != NULL) {
+ cur->content = NULL;
+ count++;
+ }
+ if (cur->children != NULL) {
+ cur = cur->children;
+ continue;
+ }
+ }
+ if (cur->next != NULL) {
+ cur = cur->next;
+ continue;
+ }
+ do {
+ cur = cur->parent;
+ if (cur == NULL)
+ break;
+ if (cur == (xmlNodePtr) root) {
+ cur = NULL;
+ break;
+ }
+ if (cur->next != NULL) {
+ cur = cur->next;
+ break;
+ }
+ } while (cur != NULL);
+ }
+
+fprintf(stderr, "Attributed %d IDs for element, cleaned up %d\n",
+ ctxt->nextid, count);
+
+ return(count);
+}
+
/**
* xsltGenerateIdFunction:
* @ctxt: the XPath Parser context
@@ -713,7 +770,39 @@ xsltGenerateIdFunction(xmlXPathParserContextPtr ctxt, int nargs){
if (obj)
xmlXPathFreeObject(obj);
- val = (long)((char *)cur - (char *)&base_address);
+ /*
+ * Try to provide stable ID for generated document:
+ * - usually ID are computed to be placed on elements via attributes
+ * so using the element as the node for the ID
+ * - the cur->content should be a correct placeholder for this, we use
+ * it to hold element node numbers in xmlXPathOrderDocElems to
+ * speed up XPath too
+ * - xsltCleanupIds() clean them up before handing the XSLT output
+ * to the API client.
+ * - other nodes types use the node address method but that should
+ * not end up in resulting document ID
+ * - we can enable this by default without risk of performance issues
+ * only the one pass xsltCleanupIds() is added
+ */
+ if (cur->type == XML_ELEMENT_NODE) {
+ if (cur->content == NULL) {
+ xsltTransformContextPtr tctxt;
+
+ tctxt = xsltXPathGetTransformContext(ctxt);
+ if (tctxt == NULL) {
+ val = (long)((char *)cur - (char *)&base_address);
+ } else {
+ tctxt->nextid++;
+ val = tctxt->nextid;
+ cur->content = (void *) (val);
+ }
+ } else {
+ val = (long) cur->content;
+ }
+ } else {
+ val = (long)((char *)cur - (char *)&base_address);
+ }
+
if (val >= 0) {
snprintf((char *)str, sizeof(str), "idp%ld", val);
} else {
diff --git a/libxslt/functions.h b/libxslt/functions.h
index 5455b7f47802..31163613f6e9 100644
--- a/libxslt/functions.h
+++ b/libxslt/functions.h
@@ -63,6 +63,13 @@ XSLTPUBFUN void XSLTCALL
xsltFunctionAvailableFunction (xmlXPathParserContextPtr ctxt,
int nargs);
+/*
+ * Cleanup for ID generation
+ */
+XSLTPUBFUN int XSLTCALL
+ xsltCleanupIds (xsltTransformContextPtr ctxt,
+ xmlNodePtr root);
+
/*
* And the registration
*/
diff --git a/libxslt/transform.c b/libxslt/transform.c
index cb43bb47d997..bc1c6afcfdd8 100644
--- a/libxslt/transform.c
+++ b/libxslt/transform.c
@@ -705,6 +705,7 @@ xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) {
cur->traceCode = (unsigned long*) &xsltDefaultTrace;
cur->xinclude = xsltGetXIncludeDefault();
cur->keyInitLevel = 0;
+ cur->nextid = 0;
return(cur);
@@ -6037,6 +6038,13 @@ xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc,
if (root != NULL) {
const xmlChar *doctype = NULL;
+ /*
+ * cleanup ids which may have been saved in Elements content ptrs
+ */
+ if (ctxt->nextid != 0) {
+ xsltCleanupIds(ctxt, root);
+ }
+
if ((root->ns != NULL) && (root->ns->prefix != NULL))
doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name);
if (doctype == NULL)
diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h
index 14343d2751c8..9d3ff5fc0c06 100644
--- a/libxslt/xsltInternals.h
+++ b/libxslt/xsltInternals.h
@@ -1786,6 +1786,8 @@ struct _xsltTransformContext {
int maxTemplateVars;
unsigned long opLimit;
unsigned long opCount;
+
+ unsigned long nextid;/* for generating stable ids */
};
/**