propagating xpath ancesstors node fix to c14n plus small performance
* c14n.c: propagating xpath ancesstors node fix to c14n plus small performance improvement to reduce number of mallocs * xpath.c: fixed ancestors axis processing for namespace nodes
diff --git a/c14n.c b/c14n.c
index 8be82bc..d8e42e0 100644
--- a/c14n.c
+++ b/c14n.c
@@ -38,6 +38,12 @@
XMLC14N_AFTER_DOCUMENT_ELEMENT = 2
} xmlC14NPosition;
+typedef struct _xmlC14NNamespaces {
+ int nsNr; /* number of nodes in the set */
+ int nsMax; /* size of the array as allocated */
+ xmlNsPtr *nsTab; /* array of nodes in no particular order */
+} xmlC14NNamespaces, *xmlC14NNamespacesPtr;
+
typedef struct _xmlC14NCtx {
/* input parameters */
xmlDocPtr doc;
@@ -48,10 +54,10 @@
/* position in the XML document */
xmlC14NPosition pos;
int parent_is_doc;
+ xmlC14NNamespacesPtr ns_rendered;
/* exclusive canonicalization */
int exclusive;
- xmlNodeSetPtr ns_rendered;
xmlChar **inclusive_ns_prefixes;
} xmlC14NCtx, *xmlC14NCtxPtr;
@@ -82,6 +88,67 @@
* The implementation internals *
* *
************************************************************************/
+#define XML_NAMESPACES_DEFAULT 16
+
+static xmlC14NNamespacesPtr
+xmlC14NNamespacesCreate() {
+ xmlC14NNamespacesPtr ret;
+
+ ret = (xmlC14NNamespacesPtr) xmlMalloc(sizeof(xmlC14NNamespaces));
+ if (ret == NULL) {
+ xmlGenericError(xmlGenericErrorContext,
+ "xmlC14NNamespacesCreate: out of memory\n");
+ return(NULL);
+ }
+ memset(ret, 0 , (size_t) sizeof(xmlC14NNamespaces));
+ return(ret);
+}
+
+static void
+xmlC14NNamespacesDestroy(xmlC14NNamespacesPtr cur) {
+ if(cur == NULL) {
+ return;
+ }
+ if(cur->nsTab != NULL) {
+ memset(cur->nsTab, 0, cur->nsMax * sizeof(xmlNsPtr));
+ xmlFree(cur->nsTab);
+ }
+ memset(cur, 0, sizeof(xmlC14NNamespaces));
+ xmlFree(cur);
+
+}
+
+static void xmlC14NNamespacesAdd(xmlC14NNamespacesPtr cur, xmlNsPtr ns) {
+ if((cur == NULL) || (ns == NULL)) {
+ return;
+ }
+
+ if (cur->nsTab == NULL) {
+ cur->nsTab = (xmlNsPtr*) xmlMalloc(XML_NAMESPACES_DEFAULT * sizeof(xmlNsPtr));
+ if (cur->nsTab == NULL) {
+ xmlGenericError(xmlGenericErrorContext,
+ "xmlC14NNamespacesAdd: out of memory\n");
+ return;
+ }
+ memset(cur->nsTab, 0 , XML_NAMESPACES_DEFAULT * sizeof(xmlNsPtr));
+ cur->nsMax = XML_NAMESPACES_DEFAULT;
+ } else if(cur->nsMax == cur->nsNr) {
+ xmlNsPtr *tmp;
+ int tmpSize;
+
+ tmpSize = 2 * cur->nsMax;
+ tmp = (xmlNsPtr*) xmlRealloc(cur->nsTab, tmpSize * sizeof(xmlNsPtr));
+ if (tmp == NULL) {
+ xmlGenericError(xmlGenericErrorContext,
+ "xmlC14NNamespacesAdd: out of memory\n");
+ return;
+ }
+ cur->nsTab = tmp;
+ cur->nsMax = tmpSize;
+ }
+ cur->nsTab[cur->nsNr++] = ns;
+}
+
/**
* xmlC14NIsVisible:
@@ -150,9 +217,9 @@
return (0);
}
- if (ctx->ns_rendered->nodeTab != NULL) {
- for (i = ctx->ns_rendered->nodeNr - 1; i >= 0; --i) {
- xmlNsPtr ns1 = (xmlNsPtr) ctx->ns_rendered->nodeTab[i];
+ if (ctx->ns_rendered->nsTab != NULL) {
+ for (i = ctx->ns_rendered->nsNr - 1; i >= 0; --i) {
+ xmlNsPtr ns1 = (xmlNsPtr) ctx->ns_rendered->nsTab[i];
if (xmlStrEqual(ns1->prefix, ns->prefix)) {
return (xmlStrEqual(ns1->href, ns->href));
@@ -267,8 +334,6 @@
xmlNsPtr ns;
xmlListPtr list;
xmlNodePtr visible_parent;
- xmlNodePtr node;
- xmlNsPtr prev;
if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
#ifdef DEBUG_C14N
@@ -293,53 +358,46 @@
/* find nearest visible parent */
visible_parent = cur->parent;
- while ((visible_parent != NULL) &&
- (!xmlC14NIsVisible(ctx, visible_parent))) {
+ while ((visible_parent != NULL) && (!xmlC14NIsVisible(ctx, visible_parent))) {
visible_parent = visible_parent->parent;
}
- /*
- * todo: the libxml XPath implementation does not create
- * nodes for all namespaces known to the node (i.e. for namespaces
- * defined in node parents). By this we need to now walk thru
- * all namespace in current node and all invisible ancesstors
- */
- node = cur;
- while (cur != visible_parent) {
- for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
- /*
- * first of all ignore default "xml" namespace and
- * already included namespace
- */
- if ((xmlC14NIsXmlNs(ns)) || (xmlListSearch(list, ns) != NULL)) {
- continue;
+ if(ctx->visible_nodes == NULL) {
+ xmlNodePtr node;
+
+ /*
+ * the libxml does not create nodes for all namespaces known
+ * to the node (i.e. for namespaces defined in node parents).
+ * By this we need to now walk thru all namespace in current
+ * node and all invisible ancesstors
+ */
+ node = cur;
+ while (cur != visible_parent) {
+ for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
+ if(!xmlC14NIsXmlNs(ns) && !xmlExcC14NIsRendered(ctx, ns)) {
+ xmlListInsert(list, ns);
+ xmlC14NNamespacesAdd(ctx->ns_rendered, ns);
+ }
+ }
+ cur = cur->parent;
+ }
+ } else {
+ int i;
+
+ /*
+ * All visible namespace nodes are in the nodes set
+ */
+ for(i = 0; i < ctx->visible_nodes->nodeNr; i++) {
+ if(ctx->visible_nodes->nodeTab[i]->type == XML_NAMESPACE_DECL) {
+ ns = (xmlNsPtr) ctx->visible_nodes->nodeTab[i];
+
+ if((ns != NULL) && (ns->next == (xmlNsPtr)cur) &&
+ !xmlC14NIsXmlNs(ns) && !xmlExcC14NIsRendered(ctx, ns)) {
+ xmlListInsert(list, ns);
+ xmlC14NNamespacesAdd(ctx->ns_rendered, ns);
+ }
}
- prev = xmlSearchNs(ctx->doc, node, ns->prefix);
- if(prev != ns) {
- /* we already processed a namespace with this name */
- continue;
- }
-
- /*
- * Lookup nearest namespace after visible parent having
- * the same prefix. Namespace included if and only if one of
- * the following:
- * - another namespace having the same prefix but
- * different value found or
- * - there is no namespaces having the same prefix and
- * it is not a default xmlns="" namespace (empty prefix
- * and empty href)
- */
- prev = xmlSearchNs(ctx->doc, visible_parent, ns->prefix);
- if ((prev == NULL) && ((xmlStrlen(ns->prefix) > 0) ||
- (xmlStrlen(ns->href) > 0))) {
- xmlListInsert(list, ns);
- } else if ((prev != NULL)
- && (!xmlStrEqual(ns->href, prev->href))) {
- xmlListInsert(list, ns);
- }
- }
- cur = cur->parent;
+ }
}
/*
@@ -355,6 +413,7 @@
return (0);
}
+
/**
* xmlExcC14NProcessNamespacesAxis:
* @ctx: the C14N context
@@ -426,12 +485,13 @@
* First of all, add all namespaces required by current node
* (i.e. node namespace and all attribute namespaces)
* we also need to check for default "xml:" namespace
+ * todo: shouldn't we check for namespaces "visibility"?
*/
ns = (cur->ns != NULL) ? cur->ns : xmlSearchNs(ctx->doc, cur, NULL);
if ((ns != NULL) && (!xmlC14NIsXmlNs(ns)) &&
(xmlListSearch(list, ns) == NULL) && !xmlExcC14NIsRendered(ctx, ns)) {
xmlListInsert(list, ns);
- xmlXPathNodeSetAdd(ctx->ns_rendered, (xmlNodePtr) ns);
+ xmlC14NNamespacesAdd(ctx->ns_rendered, ns);
}
attr = cur->properties;
while (attr != NULL) {
@@ -444,7 +504,7 @@
(!xmlC14NIsXmlNs(attr->ns)) &&
(xmlListSearch(list, attr->ns) == NULL) && (!xmlExcC14NIsRendered(ctx, attr->ns))) {
xmlListInsert(list, attr->ns);
- xmlXPathNodeSetAdd(ctx->ns_rendered, (xmlNodePtr) attr->ns);
+ xmlC14NNamespacesAdd(ctx->ns_rendered, attr->ns);
}
attr = attr->next;
}
@@ -470,7 +530,7 @@
if (xmlListSearch(list, ns) == NULL &&
!xmlExcC14NIsRendered(ctx, ns)) {
xmlListInsert(list, ns);
- xmlXPathNodeSetAdd(ctx->ns_rendered, (xmlNodePtr) ns);
+ xmlC14NNamespacesAdd(ctx->ns_rendered, ns);
}
}
}
@@ -809,8 +869,8 @@
* Save ns_rendered stack position for exclusive
* processing
*/
- if ((ctx->exclusive) && (ctx->ns_rendered != NULL)) {
- ns_rendered_pos = ctx->ns_rendered->nodeNr;
+ if (ctx->ns_rendered != NULL) {
+ ns_rendered_pos = ctx->ns_rendered->nsNr;
}
if (visible) {
@@ -883,8 +943,8 @@
* Restore ns_rendered stack position for exclusive
* processing
*/
- if ((ctx->exclusive) && (ctx->ns_rendered != NULL)) {
- ctx->ns_rendered->nodeNr = ns_rendered_pos;
+ if (ctx->ns_rendered != NULL) {
+ ctx->ns_rendered->nsNr = ns_rendered_pos;
}
return (0);
}
@@ -1148,7 +1208,7 @@
}
if (ctx->ns_rendered != NULL) {
- xmlXPathFreeNodeSet(ctx->ns_rendered);
+ xmlC14NNamespacesDestroy(ctx->ns_rendered);
}
xmlFree(ctx);
}
@@ -1226,6 +1286,7 @@
ctx->buf = buf;
ctx->parent_is_doc = 1;
ctx->pos = XMLC14N_BEFORE_DOCUMENT_ELEMENT;
+ ctx->ns_rendered = xmlC14NNamespacesCreate();
/*
* Set "exclusive" flag, create a nodes set for namespaces
@@ -1233,7 +1294,6 @@
*/
if (exclusive) {
ctx->exclusive = 1;
- ctx->ns_rendered = xmlXPathNodeSetCreate(NULL);
ctx->inclusive_ns_prefixes = inclusive_ns_prefixes;
}
return (ctx);