[libxslt] Infrastructure to store extra data in source nodes



commit adebe45f6ef9f9d036acacd8aec7411d4ea84e25
Author: Nick Wellnhofer <wellnhofer aevum de>
Date:   Wed Aug 31 15:29:57 2022 +0200

    Infrastructure to store extra data in source nodes
    
    Provide a mechanism to store bit flags in nodes from the source
    document. This will later be used to store key and id status.
    
    Provide a function to find the psvi member of a node.
    
    Revert any changes to the source document after the transformation.

 libxslt/transform.c     |  34 ++++++++++++
 libxslt/xsltInternals.h |   1 +
 libxslt/xsltutils.c     | 135 ++++++++++++++++++++++++++++++++++++++++++++++++
 libxslt/xsltutils.h     |  13 +++++
 4 files changed, 183 insertions(+)
---
diff --git a/libxslt/transform.c b/libxslt/transform.c
index cb43bb47..512eb024 100644
--- a/libxslt/transform.c
+++ b/libxslt/transform.c
@@ -5746,6 +5746,37 @@ xsltCountKeys(xsltTransformContextPtr ctxt)
     return(ctxt->nbKeys);
 }
 
+/**
+ * xsltCleanupSourceDoc:
+ * @doc:  Document
+ *
+ * Resets source node flags and ids stored in 'psvi' member.
+ */
+static void
+xsltCleanupSourceDoc(xmlDocPtr doc) {
+    xmlNodePtr cur = (xmlNodePtr) doc;
+    void **psviPtr;
+
+    while (1) {
+        xsltClearSourceNodeFlags(cur, XSLT_SOURCE_NODE_MASK);
+        psviPtr = xsltGetPSVIPtr(cur);
+        if (psviPtr)
+            *psviPtr = NULL;
+
+        if (cur->children != NULL && cur->type != XML_ENTITY_REF_NODE) {
+            cur = cur->children;
+        } else {
+            while (cur->next == NULL) {
+                cur = cur->parent;
+                if (cur == (xmlNodePtr) doc)
+                    return;
+            }
+
+            cur = cur->next;
+        }
+    }
+}
+
 /**
  * xsltApplyStylesheetInternal:
  * @style:  a parsed XSLT stylesheet
@@ -6144,6 +6175,9 @@ xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc,
     printf("# Reused variables     : %d\n", ctxt->cache->dbgReusedVars);
 #endif
 
+    if (ctxt->sourceDocDirty)
+        xsltCleanupSourceDoc(doc);
+
     if ((ctxt != NULL) && (userCtxt == NULL))
        xsltFreeTransformContext(ctxt);
 
diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h
index 14343d27..b0125c21 100644
--- a/libxslt/xsltInternals.h
+++ b/libxslt/xsltInternals.h
@@ -1786,6 +1786,7 @@ struct _xsltTransformContext {
     int maxTemplateVars;
     unsigned long opLimit;
     unsigned long opCount;
+    int sourceDocDirty;
 };
 
 /**
diff --git a/libxslt/xsltutils.c b/libxslt/xsltutils.c
index f352ca1b..9f0feb53 100644
--- a/libxslt/xsltutils.c
+++ b/libxslt/xsltutils.c
@@ -1834,6 +1834,141 @@ xsltSaveResultToString(xmlChar **doc_txt_ptr, int * doc_txt_len,
     return 0;
 }
 
+/**
+ * xsltGetSourceNodeFlags:
+ * @node:  Node from source document
+ *
+ * Returns the flags for a source node.
+ */
+int
+xsltGetSourceNodeFlags(xmlNodePtr node) {
+    /*
+     * Squeeze the bit flags into the upper bits of
+     *
+     * - 'int properties' member in struct _xmlDoc
+     * - 'xmlAttributeType atype' member in struct _xmlAttr
+     * - 'unsigned short extra' member in struct _xmlNode
+     */
+    switch (node->type) {
+        case XML_DOCUMENT_NODE:
+        case XML_HTML_DOCUMENT_NODE:
+            return ((xmlDocPtr) node)->properties >> 27;
+
+        case XML_ATTRIBUTE_NODE:
+            return ((xmlAttrPtr) node)->atype >> 27;
+
+        case XML_ELEMENT_NODE:
+        case XML_TEXT_NODE:
+        case XML_CDATA_SECTION_NODE:
+        case XML_PI_NODE:
+        case XML_COMMENT_NODE:
+            return node->extra >> 12;
+
+        default:
+            return 0;
+    }
+}
+
+/**
+ * xsltSetSourceNodeFlags:
+ * @node:  Node from source document
+ * @flags:  Flags
+ *
+ * Sets the specified flags to 1.
+ *
+ * Returns 0 on success, -1 on error.
+ */
+int
+xsltSetSourceNodeFlags(xsltTransformContextPtr ctxt, xmlNodePtr node,
+                       int flags) {
+    if (node->doc == ctxt->initialContextDoc)
+        ctxt->sourceDocDirty = 1;
+
+    switch (node->type) {
+        case XML_DOCUMENT_NODE:
+        case XML_HTML_DOCUMENT_NODE:
+            ((xmlDocPtr) node)->properties |= flags << 27;
+            return 0;
+
+        case XML_ATTRIBUTE_NODE:
+            ((xmlAttrPtr) node)->atype |= flags << 27;
+            return 0;
+
+        case XML_ELEMENT_NODE:
+        case XML_TEXT_NODE:
+        case XML_CDATA_SECTION_NODE:
+        case XML_PI_NODE:
+        case XML_COMMENT_NODE:
+            node->extra |= flags << 12;
+            return 0;
+
+        default:
+            return -1;
+    }
+}
+
+/**
+ * xsltClearSourceNodeFlags:
+ * @node:  Node from source document
+ * @flags:  Flags
+ *
+ * Sets the specified flags to 0.
+ *
+ * Returns 0 on success, -1 on error.
+ */
+int
+xsltClearSourceNodeFlags(xmlNodePtr node, int flags) {
+    switch (node->type) {
+        case XML_DOCUMENT_NODE:
+        case XML_HTML_DOCUMENT_NODE:
+            ((xmlDocPtr) node)->properties &= ~(flags << 27);
+            return 0;
+
+        case XML_ATTRIBUTE_NODE:
+            ((xmlAttrPtr) node)->atype &= ~(flags << 27);
+            return 0;
+
+        case XML_ELEMENT_NODE:
+        case XML_TEXT_NODE:
+        case XML_CDATA_SECTION_NODE:
+        case XML_PI_NODE:
+        case XML_COMMENT_NODE:
+            node->extra &= ~(flags << 12);
+            return 0;
+
+        default:
+            return -1;
+    }
+}
+
+/**
+ * xsltGetPSVIPtr:
+ * @cur:  Node
+ *
+ * Returns a pointer to the psvi member of a node or NULL on error.
+ */
+void **
+xsltGetPSVIPtr(xmlNodePtr cur) {
+    switch (cur->type) {
+        case XML_DOCUMENT_NODE:
+        case XML_HTML_DOCUMENT_NODE:
+            return &((xmlDocPtr) cur)->psvi;
+
+        case XML_ATTRIBUTE_NODE:
+            return &((xmlAttrPtr) cur)->psvi;
+
+        case XML_ELEMENT_NODE:
+        case XML_TEXT_NODE:
+        case XML_CDATA_SECTION_NODE:
+        case XML_PI_NODE:
+        case XML_COMMENT_NODE:
+            return &cur->psvi;
+
+        default:
+            return NULL;
+    }
+}
+
 #ifdef WITH_PROFILER
 
 /************************************************************************
diff --git a/libxslt/xsltutils.h b/libxslt/xsltutils.h
index 7a12f7b3..65ef78e0 100644
--- a/libxslt/xsltutils.h
+++ b/libxslt/xsltutils.h
@@ -244,6 +244,19 @@ XSLTPUBFUN xmlXPathCompExprPtr XSLTCALL
                                                 const xmlChar *str,
                                                 int flags);
 
+#ifdef IN_LIBXSLT
+#define XSLT_SOURCE_NODE_MASK       15
+int
+xsltGetSourceNodeFlags(xmlNodePtr node);
+int
+xsltSetSourceNodeFlags(xsltTransformContextPtr ctxt, xmlNodePtr node,
+                       int flags);
+int
+xsltClearSourceNodeFlags(xmlNodePtr node, int flags);
+void **
+xsltGetPSVIPtr(xmlNodePtr cur);
+#endif
+
 #ifdef WITH_PROFILER
 /*
  * Profiling.


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]