1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
From: Daniel Veillard <veillard@redhat.com>
Date: Sun, 29 Oct 2017 01:04:54 +0200
Subject: 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(-)
--- a/libxslt/functions.c
+++ b/libxslt/functions.c
@@ -684,6 +684,63 @@
}
/**
+ * 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
* @nargs: the number of arguments
@@ -734,7 +791,39 @@
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 {
--- a/libxslt/functions.h
+++ b/libxslt/functions.h
@@ -64,6 +64,13 @@
int nargs);
/*
+ * Cleanup for ID generation
+ */
+XSLTPUBFUN int XSLTCALL
+ xsltCleanupIds (xsltTransformContextPtr ctxt,
+ xmlNodePtr root);
+
+/*
* And the registration
*/
--- a/libxslt/transform.c
+++ b/libxslt/transform.c
@@ -706,6 +706,7 @@
cur->traceCode = (unsigned long*) &xsltDefaultTrace;
cur->xinclude = xsltGetXIncludeDefault();
cur->keyInitLevel = 0;
+ cur->nextid = 0;
return(cur);
@@ -6038,6 +6039,13 @@
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)
--- a/libxslt/xsltInternals.h
+++ b/libxslt/xsltInternals.h
@@ -1786,6 +1786,8 @@
int maxTemplateVars;
unsigned long opLimit;
unsigned long opCount;
+
+ unsigned long nextid;/* for generating stable ids */
};
/**
|