--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xmlsecurityengine/xmlsec/src/xmlsec_xmltree.c Thu Dec 17 09:29:21 2009 +0200
@@ -0,0 +1,1792 @@
+/**
+ * XML Security Library (http://www.aleksey.com/xmlsec).
+ *
+ * Common XML Doc utility functions
+ *
+ * This is free software; see Copyright file in the source
+ * distribution for preciese wording.
+ *
+ * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com>
+ * Portion Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
+ */
+#include "xmlsec_globals.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <libxml2_tree.h>
+#include <libxml2_valid.h>
+#include <libxml2_xpath.h>
+#include <libxml2_xpathinternals.h>
+#include <libxml2_globals.h>
+
+#include "xmlsec_xmlsec.h"
+#include "xmlsec_xmltree.h"
+#include "xmlsec_parser.h"
+#include "xmlsec_private.h"
+#include "xmlsec_base64.h"
+#include "xmlsec_errors.h"
+#include "xmlsec_templates.h"
+
+/**
+ * xmlSecFindChild:
+ * @parent: the pointer to XML node.
+ * @name: the name.
+ * @ns: the namespace href (may be NULL).
+ *
+ * Searches a direct child of the @parent node having given name and
+ * namespace href.
+ *
+ * Returns the pointer to the found node or NULL if an error occurs or
+ * node is not found.
+ */
+EXPORT_C
+xmlNodePtr
+xmlSecFindChild(const xmlNodePtr parent, const xmlChar *name, const xmlChar *ns) {
+ xmlNodePtr cur;
+
+ xmlSecAssert2(parent != NULL, NULL);
+ xmlSecAssert2(name != NULL, NULL);
+
+ cur = parent->children;
+ while(cur != NULL) {
+ if(cur->type == XML_ELEMENT_NODE) {
+ if(xmlSecCheckNodeName(cur, name, ns)) {
+ return(cur);
+ }
+ }
+ cur = cur->next;
+ }
+ return(NULL);
+}
+
+/**
+ * xmlSecFindParent:
+ * @cur: the pointer to an XML node.
+ * @name: the name.
+ * @ns: the namespace href (may be NULL).
+ *
+ * Searches the ancestors axis of the @cur node for a node having given name
+ * and namespace href.
+ *
+ * Returns the pointer to the found node or NULL if an error occurs or
+ * node is not found.
+ */
+EXPORT_C
+xmlNodePtr
+xmlSecFindParent(const xmlNodePtr cur, const xmlChar *name, const xmlChar *ns) {
+ xmlSecAssert2(cur != NULL, NULL);
+ xmlSecAssert2(name != NULL, NULL);
+
+ if(xmlSecCheckNodeName(cur, name, ns)) {
+ return(cur);
+ } else if(cur->parent != NULL) {
+ return(xmlSecFindParent(cur->parent, name, ns));
+ }
+ return(NULL);
+}
+
+/**
+ * xmlSecFindNode:
+ * @parent: the pointer to XML node.
+ * @name: the name.
+ * @ns: the namespace href (may be NULL).
+ *
+ * Searches all children of the @parent node having given name and
+ * namespace href.
+ *
+ * Returns the pointer to the found node or NULL if an error occurs or
+ * node is not found.
+ */
+EXPORT_C
+xmlNodePtr
+xmlSecFindNode(const xmlNodePtr parent, const xmlChar *name, const xmlChar *ns) {
+ xmlNodePtr cur;
+ xmlNodePtr ret;
+
+ xmlSecAssert2(name != NULL, NULL);
+
+ cur = parent;
+ while(cur != NULL) {
+ if((cur->type == XML_ELEMENT_NODE) && xmlSecCheckNodeName(cur, name, ns)) {
+ return(cur);
+ }
+ if(cur->children != NULL) {
+ ret = xmlSecFindNode(cur->children, name, ns);
+ if(ret != NULL) {
+ return(ret);
+ }
+ }
+ cur = cur->next;
+ }
+ return(NULL);
+}
+
+/**
+ * xmlSecGetNodeNsHref:
+ * @cur: the pointer to node.
+ *
+ * Get's node's namespace href.
+ *
+ * Returns node's namespace href.
+ */
+EXPORT_C
+const xmlChar*
+xmlSecGetNodeNsHref(const xmlNodePtr cur) {
+ xmlNsPtr ns;
+
+ xmlSecAssert2(cur != NULL, NULL);
+
+ /* do we have a namespace in the node? */
+ if(cur->ns != NULL) {
+ return(cur->ns->href);
+ }
+
+ /* search for default namespace */
+ ns = xmlSearchNs(cur->doc, cur, NULL);
+ if(ns != NULL) {
+ return(ns->href);
+ }
+
+ return(NULL);
+}
+
+/**
+ * xmlSecCheckNodeName:
+ * @cur: the pointer to an XML node.
+ * @name: the name,
+ * @ns: the namespace href.
+ *
+ * Checks that the node has a given name and a given namespace href.
+ *
+ * Returns 1 if the node matches or 0 otherwise.
+ */
+EXPORT_C
+int
+xmlSecCheckNodeName(const xmlNodePtr cur, const xmlChar *name, const xmlChar *ns) {
+ xmlSecAssert2(cur != NULL, 0);
+
+ return(xmlStrEqual(cur->name, name) &&
+ xmlStrEqual(xmlSecGetNodeNsHref(cur), ns));
+}
+
+/**
+ * xmlSecAddChild:
+ * @parent: the pointer to an XML node.
+ * @name: the new node name.
+ * @ns: the new node namespace.
+ *
+ * Adds a child to the node @parent with given @name and namespace @ns.
+ *
+ * Returns pointer to the new node or NULL if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr
+xmlSecAddChild(xmlNodePtr parent, const xmlChar *name, const xmlChar *ns) {
+ xmlNodePtr cur;
+ xmlNodePtr text;
+
+ xmlSecAssert2(parent != NULL, NULL);
+ xmlSecAssert2(name != NULL, NULL);
+
+ if(xmlGetNewLineFlag() && parent->children == NULL) {
+ text = xmlNewText(xmlSecStringCR);
+ if(text == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlNewText",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(NULL);
+ }
+ xmlAddChild(parent, text);
+ }
+
+ cur = xmlNewChild(parent, NULL, name, NULL);
+ if(cur == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlNewChild",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(NULL);
+ }
+
+ /* namespaces support */
+ if(ns != NULL) {
+ xmlNsPtr nsPtr;
+
+ nsPtr = xmlSearchNsByHref(cur->doc, cur, ns);
+ if((nsPtr == NULL) || !xmlStrEqual(nsPtr->href, ns)) {
+ nsPtr = xmlNewNs(cur, ns, NULL);
+ }
+ xmlSetNs(cur, nsPtr);
+ }
+
+ if(xmlGetNewLineFlag())
+ {
+ text = xmlNewText(xmlSecStringCR);
+ if(text == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlNewText",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(NULL);
+ }
+ xmlAddChild(parent, text);
+ }
+ return(cur);
+}
+
+/**
+ * xmlSecAddChildNode:
+ * @parent: the pointer to an XML node.
+ * @child: the new node.
+ *
+ * Adds @child node to the @parent node.
+ *
+ * Returns pointer to the new node or NULL if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr
+xmlSecAddChildNode(xmlNodePtr parent, xmlNodePtr child) {
+ xmlNodePtr text;
+
+ xmlSecAssert2(parent != NULL, NULL);
+ xmlSecAssert2(child != NULL, NULL);
+
+ if(xmlGetNewLineFlag() && parent->children == NULL) {
+ text = xmlNewText(xmlSecStringCR);
+ if(text == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlNewText",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(NULL);
+ }
+ xmlAddChild(parent, text);
+ }
+
+ xmlAddChild(parent, child);
+
+ if(xmlGetNewLineFlag())
+ {
+ text = xmlNewText(xmlSecStringCR);
+ if(text == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlNewText",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(NULL);
+ }
+ xmlAddChild(parent, text);
+ }
+
+ return(child);
+}
+
+/**
+ * xmlSecAddNextSibling
+ * @node: the pointer to an XML node.
+ * @name: the new node name.
+ * @ns: the new node namespace.
+ *
+ * Adds next sibling to the node @node with given @name and namespace @ns.
+ *
+ * Returns pointer to the new node or NULL if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr
+xmlSecAddNextSibling(xmlNodePtr node, const xmlChar *name, const xmlChar *ns) {
+ xmlNodePtr cur;
+ xmlNodePtr text;
+
+ xmlSecAssert2(node != NULL, NULL);
+ xmlSecAssert2(name != NULL, NULL);
+
+ cur = xmlNewNode(NULL, name);
+ if(cur == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlNewNode",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(NULL);
+ }
+ xmlAddNextSibling(node, cur);
+
+ /* namespaces support */
+ if(ns != NULL) {
+ xmlNsPtr nsPtr;
+
+ nsPtr = xmlSearchNsByHref(cur->doc, cur, ns);
+ if((nsPtr == NULL) || !xmlStrEqual(nsPtr->href, ns)) {
+ nsPtr = xmlNewNs(cur, ns, NULL);
+ }
+ xmlSetNs(cur, nsPtr);
+ }
+
+ if(xmlGetNewLineFlag())
+ {
+ text = xmlNewText(xmlSecStringCR);
+ if(text == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlNewText",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(NULL);
+ }
+ xmlAddNextSibling(node, text);
+ }
+
+ return(cur);
+}
+
+/**
+ * xmlSecAddPrevSibling
+ * @node: the pointer to an XML node.
+ * @name: the new node name.
+ * @ns: the new node namespace.
+ *
+ * Adds prev sibling to the node @node with given @name and namespace @ns.
+ *
+ * Returns pointer to the new node or NULL if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr
+xmlSecAddPrevSibling(xmlNodePtr node, const xmlChar *name, const xmlChar *ns) {
+ xmlNodePtr cur;
+ xmlNodePtr text;
+
+ xmlSecAssert2(node != NULL, NULL);
+ xmlSecAssert2(name != NULL, NULL);
+
+ cur = xmlNewNode(NULL, name);
+ if(cur == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlNewNode",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(NULL);
+ }
+ xmlAddPrevSibling(node, cur);
+
+ /* namespaces support */
+ if(ns != NULL) {
+ xmlNsPtr nsPtr;
+
+ nsPtr = xmlSearchNsByHref(cur->doc, cur, ns);
+ if((nsPtr == NULL) || !xmlStrEqual(nsPtr->href, ns)) {
+ nsPtr = xmlNewNs(cur, ns, NULL);
+ if (nsPtr == NULL)
+ return(NULL);
+ }
+ xmlSetNs(cur, nsPtr);
+ }
+
+ if(xmlGetNewLineFlag())
+ {
+ text = xmlNewText(xmlSecStringCR);
+ if(text == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlNewText",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(NULL);
+ }
+ xmlAddPrevSibling(node, text);
+ }
+ return(cur);
+}
+
+/**
+ * xmlSecGetNextElementNode:
+ * @cur: the pointer to an XML node.
+ *
+ * Seraches for the next element node.
+ *
+ * Returns the pointer to next element node or NULL if it is not found.
+ */
+EXPORT_C
+xmlNodePtr
+xmlSecGetNextElementNode(xmlNodePtr cur) {
+
+ while((cur != NULL) && (cur->type != XML_ELEMENT_NODE)) {
+ cur = cur->next;
+ }
+ return(cur);
+}
+
+/**
+ * xmlSecReplaceNode:
+ * @node: the current node.
+ * @newNode: the new node.
+ *
+ * Swaps the @node and @newNode in the XML tree.
+ *
+ * Returns 0 on success or a negative value if an error occurs.
+ */
+EXPORT_C
+int
+xmlSecReplaceNode(xmlNodePtr node, xmlNodePtr newNode) {
+ xmlNodePtr oldNode;
+ int restoreRoot = 0;
+
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(newNode != NULL, -1);
+
+ /* fix documents children if necessary first */
+ if((node->doc != NULL) && (node->doc->children == node)) {
+ node->doc->children = node->next;
+ restoreRoot = 1;
+ }
+ if((newNode->doc != NULL) && (newNode->doc->children == newNode)) {
+ newNode->doc->children = newNode->next;
+ }
+
+ oldNode = xmlReplaceNode(node, newNode);
+ if(oldNode == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlReplaceNode",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ if(restoreRoot != 0) {
+ xmlDocSetRootElement(oldNode->doc, newNode);
+ }
+
+ xmlFreeNode(oldNode);
+ return(0);
+}
+
+/**
+ * xmlSecReplaceContent
+ * @node: the current node.
+ * @newNode: the new node.
+ *
+ * Swaps the content of @node and @newNode.
+ *
+ * Returns 0 on success or a negative value if an error occurs.
+ */
+EXPORT_C
+int
+xmlSecReplaceContent(xmlNodePtr node, xmlNodePtr newNode) {
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(newNode != NULL, -1);
+
+ xmlUnlinkNode(newNode);
+ xmlSetTreeDoc(newNode, node->doc);
+ xmlNodeSetContent(node, NULL);
+ xmlAddChild(node, newNode);
+ xmlSetTreeDoc(newNode, node->doc);
+
+ return(0);
+}
+
+
+/**
+ * xmlSecReplaceNodeBuffer:
+ * @node: the current node.
+ * @buffer: the XML data.
+ * @size: the XML data size.
+ *
+ * Swaps the @node and the parsed XML data from the @buffer in the XML tree.
+ *
+ * Returns 0 on success or a negative value if an error occurs.
+ */
+EXPORT_C
+int
+xmlSecReplaceNodeBuffer(xmlNodePtr node,
+ const xmlSecByte *buffer, xmlSecSize size) {
+ xmlNodePtr results = NULL;
+ xmlNodePtr next = NULL;
+ xmlNodePtr tmp = NULL; // MK added
+
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(node->parent != NULL, -1);
+
+ /* parse buffer in the context of node's parent */
+ if(xmlParseInNodeContext(node->parent, (const char*)buffer, size, XML_PARSE_NODICT, &results) != XML_ERR_OK) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlParseInNodeContext",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ "Failed to parse content");
+ return(-1);
+ }
+
+ if(results == NULL && node->parent->type == XML_DOCUMENT_NODE)
+ {
+ tmp = node->last;
+ xmlUnlinkNode(tmp);
+ results = tmp;
+ }
+
+ /* add new nodes */
+ while (results != NULL) {
+ next = results->next;
+ xmlAddPrevSibling(node, results);
+ results = next;
+ }
+
+ /* remove old node */
+ xmlUnlinkNode(node);
+ xmlFreeNode(node);
+
+ return(0);
+}
+
+/**
+ * xmlSecAddIDs:
+ * @doc: the pointer to an XML document.
+ * @cur: the pointer to an XML node.
+ * @ids: the pointer to a NULL terminated list of ID attributes.
+ *
+ * Walks thru all children of the @cur node and adds all attributes
+ * from the @ids list to the @doc document IDs attributes hash.
+ */
+EXPORT_C
+void
+xmlSecAddIDs(xmlDocPtr doc, xmlNodePtr cur, const xmlChar** ids) {
+ xmlNodePtr children = NULL;
+
+ xmlSecAssert(doc != NULL);
+ xmlSecAssert(ids != NULL);
+
+ if((cur != NULL) && (cur->type == XML_ELEMENT_NODE)) {
+ xmlAttrPtr attr;
+ xmlAttrPtr tmp;
+ int i;
+ xmlChar* name;
+
+ for(attr = cur->properties; attr != NULL; attr = attr->next) {
+ for(i = 0; ids[i] != NULL; ++i) {
+ if(xmlStrEqual(attr->name, ids[i])) {
+ name = xmlNodeListGetString(doc, attr->children, 1);
+ if(name != NULL) {
+ tmp = xmlGetID(doc, name);
+ if(tmp == NULL) {
+ xmlAddID(NULL, doc, name, attr);
+ } else if(tmp != attr) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ NULL,
+ XMLSEC_ERRORS_R_INVALID_DATA,
+ "id=%s already defined",
+ xmlSecErrorsSafeString(name));
+ }
+ xmlFree(name);
+ }
+ }
+ }
+ }
+
+ children = cur->children;
+ } else if(cur == NULL) {
+ children = doc->children;
+ }
+
+ while(children != NULL) {
+ if(children->type == XML_ELEMENT_NODE) {
+ xmlSecAddIDs(doc, children, ids);
+ }
+ children = children->next;
+ }
+}
+
+/**
+ * xmlSecGenerateAndAddID:
+ * @node: the node to ID attr to.
+ * @attrName: the ID attr name.
+ * @prefix: the prefix to add to the generated ID (can be NULL).
+ * @len: the length of ID.
+ *
+ * Generates a unique ID in the format <@prefix>base64-encoded(@len random bytes)
+ * and puts it in the attribute @attrName.
+ *
+ * Returns 0 on success or a negative value if an error occurs.
+ */
+EXPORT_C
+int
+xmlSecGenerateAndAddID(xmlNodePtr node, const xmlChar* attrName, const xmlChar* prefix, xmlSecSize len) {
+ xmlChar* id;
+ int count;
+
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(attrName != NULL, -1);
+
+ /* we will try 5 times before giving up */
+ for(count = 0; count < 5; count++) {
+ id = xmlSecGenerateID(prefix, len);
+ if(id == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecGenerateID",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ if((node->doc == NULL) || (xmlGetID(node->doc, id) == NULL)) {
+ /* this is a unique ID in the document and we can use it */
+ if(xmlSetProp(node, attrName, id) == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSetProp",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlFree(id);
+ return(-1);
+ }
+
+ xmlFree(id);
+ return(0);
+ }
+ xmlFree(id);
+ }
+
+ return(-1);
+}
+
+/**
+ * xmlSecGenerateID:
+ * @prefix: the prefix to add to the generated ID (can be NULL).
+ * @len: the length of ID.
+ *
+ * Generates a unique ID in the format <@prefix>base64-encoded(@len random bytes).
+ * The caller is responsible for freeing returned string using @xmlFree function.
+ *
+ * Returns pointer to generated ID string or NULL if an error occurs.
+ */
+EXPORT_C
+xmlChar*
+xmlSecGenerateID(const xmlChar* prefix, xmlSecSize len) {
+ xmlSecBuffer buffer;
+ xmlSecSize i, binLen;
+ xmlChar* res;
+ xmlChar* p;
+ int ret;
+
+ xmlSecAssert2(len > 0, NULL);
+
+ /* we will do base64 decoding later */
+ binLen = (3 * len + 1) / 4;
+
+ ret = xmlSecBufferInitialize(&buffer, binLen + 1);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBufferInitialize",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(NULL);
+ }
+ xmlSecAssert2(xmlSecBufferGetData(&buffer) != NULL, NULL);
+ xmlSecAssert2(xmlSecBufferGetMaxSize(&buffer) >= binLen, NULL);
+
+ ret = xmlSecBufferSetSize(&buffer, binLen);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBufferSetSize",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlSecBufferFinalize(&buffer);
+ return(NULL);
+ }
+ xmlSecAssert2(xmlSecBufferGetSize(&buffer) == binLen, NULL);
+
+ /* create random bytes */
+ for(i = 0; i < binLen; i++) {
+ (xmlSecBufferGetData(&buffer)) [i] = (xmlSecByte) (256.0 * rand() / (RAND_MAX + 1.0));
+ }
+
+ /* base64 encode random bytes */
+ res = xmlSecBase64Encode(xmlSecBufferGetData(&buffer), xmlSecBufferGetSize(&buffer), 0);
+ if((res == NULL) || (xmlStrlen(res) == 0)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBase64Encode",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlSecBufferFinalize(&buffer);
+ return(NULL);
+ }
+ xmlSecBufferFinalize(&buffer);
+
+ /* truncate the generated id attribute if needed */
+ if(xmlStrlen(res) > (int)len) {
+ res[len] = '\0';
+ }
+
+ /* we need to cleanup base64 encoded id because ID attr can't have '+' or '/' characters */
+ for(p = res; (*p) != '\0'; p++) {
+ if(((*p) == '+') || ((*p) == '/')) {
+ (*p) = '_';
+ }
+ }
+
+ /* add prefix if exist */
+ if(prefix) {
+ xmlChar* tmp;
+ xmlSecSize tmpLen;
+
+ tmpLen = xmlStrlen(prefix) + xmlStrlen(res) + 1;
+ tmp = xmlMalloc(tmpLen + 1);
+ if(tmp == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlMalloc",
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlFree(res);
+ return(NULL);
+ }
+
+ xmlSecStrPrintf(tmp, tmpLen, BAD_CAST "%s%s", prefix, res);
+ xmlFree(res);
+ res = tmp;
+ } else {
+ /* no prefix: check that ID attribute starts from a letter */
+ if(!(((res[0] >= 'A') && (res[0] <= 'Z')) ||
+ ((res[0] >= 'a') && (res[0] <= 'z')))) {
+ res[0] = 'A';
+ }
+ }
+
+ return(res);
+}
+
+
+/**
+ * xmlSecCreateTree:
+ * @rootNodeName: the root node name.
+ * @rootNodeNs: the root node namespace (otpional).
+ *
+ * Creates a new XML tree with one root node @rootNodeName.
+ *
+ * Returns pointer to the newly created tree or NULL if an error occurs.
+ */
+EXPORT_C
+xmlDocPtr
+xmlSecCreateTree(const xmlChar* rootNodeName, const xmlChar* rootNodeNs) {
+ xmlDocPtr doc;
+ xmlNodePtr root;
+ xmlNsPtr ns;
+
+ xmlSecAssert2(rootNodeName != NULL, NULL);
+
+ /* create doc */
+ doc = xmlNewDoc(BAD_CAST "1.0");
+ if(doc == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlNewDoc",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(NULL);
+ }
+
+ /* create root node */
+ root = xmlNewDocNode(doc, NULL, rootNodeName, NULL);
+ if(root == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlNewDocNode",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ "node=Keys");
+ xmlFreeDoc(doc);
+ return(NULL);
+ }
+ xmlDocSetRootElement(doc, root);
+
+ /* and set root node namespace */
+ ns = xmlNewNs(root, rootNodeNs, NULL);
+ if(ns == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlNewNs",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ "ns=%s",
+ xmlSecErrorsSafeString(rootNodeNs));
+ xmlFreeDoc(doc);
+ return(NULL);
+ }
+ xmlSetNs(root, ns);
+
+ return(doc);
+}
+
+/**
+ * xmlSecIsEmptyNode:
+ * @node: the node to check
+ *
+ * Checks whethere the @node is empty (i.e. has only whitespaces children).
+ *
+ * Returns 1 if @node is empty, 0 otherwise or a negative value if an error occurs.
+ */
+EXPORT_C
+int
+xmlSecIsEmptyNode(xmlNodePtr node) {
+ xmlChar* content;
+ int res;
+
+ xmlSecAssert2(node != NULL, -1);
+
+ if(xmlSecGetNextElementNode(node->children) != NULL) {
+ return(0);
+ }
+
+ content = xmlNodeGetContent(node);
+ if(content == NULL) {
+ return(1);
+ }
+
+ res = xmlSecIsEmptyString(content);
+ xmlFree(content);
+ return(res);
+}
+
+/**
+ * xmlSecIsEmptyString:
+ * @str: the string to check
+ *
+ * Checks whethere the @str is empty (i.e. has only whitespaces children).
+ *
+ * Returns 1 if @str is empty, 0 otherwise or a negative value if an error occurs.
+ */
+EXPORT_C
+int
+xmlSecIsEmptyString(const xmlChar* str) {
+ xmlSecAssert2(str != NULL, -1);
+
+ for( ;*str != '\0'; ++str) {
+ if(!isspace((int)(*str))) {
+ return(0);
+ }
+ }
+ return(1);
+}
+
+/**
+ * xmlSecGetQName:
+ * @node: the context node.
+ * @href: the QName href (can be NULL).
+ * @local: the QName local part.
+ *
+ * Creates QName (prefix:local) from @href and @local in the context of the @node.
+ * Caller is responsible for freeing returned string with xmlFree.
+ *
+ * Returns qname or NULL if an error occurs.
+ */
+EXPORT_C
+xmlChar*
+xmlSecGetQName(xmlNodePtr node, const xmlChar* href, const xmlChar* local) {
+ xmlChar* qname;
+ xmlNsPtr ns;
+
+ xmlSecAssert2(node != NULL, NULL);
+ xmlSecAssert2(local != NULL, NULL);
+
+ /* we don't want to create namespace node ourselves because
+ * it might cause collisions */
+ ns = xmlSearchNsByHref(node->doc, node, href);
+ if((ns == NULL) && (href != NULL)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSearchNsByHref",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ "node=%s,href=%s",
+ xmlSecErrorsSafeString(node->name),
+ xmlSecErrorsSafeString(href));
+ return(NULL);
+ }
+
+ if((ns != NULL) && (ns->prefix != NULL)) {
+ xmlSecSize len;
+
+ len = xmlStrlen(local) + xmlStrlen(ns->prefix) + 4;
+ qname = xmlMalloc(len);
+ if(qname == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlMalloc",
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(node->name));
+ return(NULL);
+ }
+ xmlSecStrPrintf(qname, len, BAD_CAST "%s:%s", ns->prefix, local);
+ } else {
+ qname = xmlStrdup(local);
+ if(qname == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlStrdup",
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(node->name));
+ return(NULL);
+ }
+ }
+
+
+ return(qname);
+}
+
+
+/*************************************************************************
+ *
+ * QName <-> Integer mapping
+ *
+ ************************************************************************/
+/**
+ * xmlSecQName2IntegerGetInfo:
+ * @info: the qname<->integer mapping information.
+ * @intValue: the integer value.
+ *
+ * Maps integer @intValue to a QName prefix.
+ *
+ * Returns the QName info that is mapped to @intValue or NULL if such value
+ * is not found.
+ */
+EXPORT_C
+xmlSecQName2IntegerInfoConstPtr
+xmlSecQName2IntegerGetInfo(xmlSecQName2IntegerInfoConstPtr info, int intValue) {
+ unsigned int ii;
+
+ xmlSecAssert2(info != NULL, NULL);
+
+ for(ii = 0; info[ii].qnameLocalPart != NULL; ii++) {
+ if(info[ii].intValue == intValue) {
+ return(&info[ii]);
+ }
+ }
+
+ return(NULL);
+}
+
+/**
+ * xmlSecQName2IntegerGetInteger:
+ * @info: the qname<->integer mapping information.
+ * @qnameHref: the qname href value.
+ * @qnameLocalPart: the qname local part value.
+ * @intValue: the pointer to result integer value.
+ *
+ * Maps qname qname to an integer and returns it in @intValue.
+ *
+ * Returns 0 on success or a negative value if an error occurs,
+ */
+EXPORT_C
+int
+xmlSecQName2IntegerGetInteger(xmlSecQName2IntegerInfoConstPtr info,
+ const xmlChar* qnameHref, const xmlChar* qnameLocalPart,
+ int* intValue) {
+ unsigned int ii;
+
+ xmlSecAssert2(info != NULL, -1);
+ xmlSecAssert2(qnameLocalPart != NULL, -1);
+ xmlSecAssert2(intValue != NULL, -1);
+
+ for(ii = 0; info[ii].qnameLocalPart != NULL; ii++) {
+ if(xmlStrEqual(info[ii].qnameLocalPart, qnameLocalPart) &&
+ xmlStrEqual(info[ii].qnameHref, qnameHref)) {
+ (*intValue) = info[ii].intValue;
+ return(0);
+ }
+ }
+
+ return(-1);
+}
+
+/**
+ * xmlSecQName2IntegerGetIntegerFromInteger:
+ * @info: the qname<->integer mapping information.
+ * @node: the pointer to node.
+ * @qname: the qname string.
+ * @intValue: the pointer to result integer value.
+ *
+ * Converts @qname into integer in context of @node.
+ *
+ * Returns 0 on success or a negative value if an error occurs,
+ */
+EXPORT_C
+int
+xmlSecQName2IntegerGetIntegerFromString(xmlSecQName2IntegerInfoConstPtr info,
+ xmlNodePtr node, const xmlChar* qname,
+ int* intValue) {
+ const xmlChar* qnameLocalPart = NULL;
+ xmlChar* qnamePrefix = NULL;
+ const xmlChar* qnameHref;
+ xmlNsPtr ns;
+ int ret;
+
+ xmlSecAssert2(info != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(qname != NULL, -1);
+ xmlSecAssert2(intValue != NULL, -1);
+
+ qnameLocalPart = xmlStrchr(qname, ':');
+ if(qnameLocalPart != NULL) {
+ qnamePrefix = xmlStrndup(qname, qnameLocalPart - qname);
+ if(qnamePrefix == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlStrndup",
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ "node=%s,value=%s",
+ xmlSecErrorsSafeString(node->name),
+ xmlSecErrorsSafeString(qname));
+ return(-1);
+ }
+ qnameLocalPart++;
+ } else {
+ qnamePrefix = NULL;
+ qnameLocalPart = qname;
+ }
+
+ /* search namespace href */
+ ns = xmlSearchNs(node->doc, node, qnamePrefix);
+ if((ns == NULL) && (qnamePrefix != NULL)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSearchNs",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ "node=%s,qnamePrefix=%s",
+ xmlSecErrorsSafeString(node->name),
+ xmlSecErrorsSafeString(qnamePrefix));
+ if(qnamePrefix != NULL) {
+ xmlFree(qnamePrefix);
+ }
+ return(-1);
+ }
+ qnameHref = (ns != NULL) ? ns->href : BAD_CAST NULL;
+
+ /* and finally search for integer */
+ ret = xmlSecQName2IntegerGetInteger(info, qnameHref, qnameLocalPart, intValue);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecQName2IntegerGetInteger",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s,qnameLocalPart=%s,qnameHref=%s",
+ xmlSecErrorsSafeString(node->name),
+ xmlSecErrorsSafeString(qnameLocalPart),
+ xmlSecErrorsSafeString(qnameHref));
+ if(qnamePrefix != NULL) {
+ xmlFree(qnamePrefix);
+ }
+ return(-1);
+ }
+
+ if(qnamePrefix != NULL) {
+ xmlFree(qnamePrefix);
+ }
+ return(0);
+}
+
+
+/**
+ * xmlSecQName2IntegerGetStringFromInteger:
+ * @info: the qname<->integer mapping information.
+ * @node: the pointer to node.
+ * @intValue: the integer value.
+ *
+ * Creates qname string for @intValue in context of given @node. Caller
+ * is responsible for freeing returned string with @xmlFree.
+ *
+ * Returns pointer to newly allocated string on success or NULL if an error occurs,
+ */
+EXPORT_C
+xmlChar*
+xmlSecQName2IntegerGetStringFromInteger(xmlSecQName2IntegerInfoConstPtr info,
+ xmlNodePtr node, int intValue) {
+ xmlSecQName2IntegerInfoConstPtr qnameInfo;
+
+ xmlSecAssert2(info != NULL, NULL);
+ xmlSecAssert2(node != NULL, NULL);
+
+ qnameInfo = xmlSecQName2IntegerGetInfo(info, intValue);
+ if(qnameInfo == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecQName2IntegerGetInfo",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s,intValue=%d",
+ xmlSecErrorsSafeString(node->name),
+ intValue);
+ return(NULL);
+ }
+
+ return (xmlSecGetQName(node, qnameInfo->qnameHref, qnameInfo->qnameLocalPart));
+}
+
+/**
+ * xmlSecQName2IntegerNodeRead:
+ * @info: the qname<->integer mapping information.
+ * @node: the pointer to node.
+ * @intValue: the pointer to result integer value.
+ *
+ * Reads the content of @node and converts it to an integer using mapping
+ * from @info.
+ *
+ * Returns 0 on success or a negative value if an error occurs,
+ */
+EXPORT_C
+int
+xmlSecQName2IntegerNodeRead(xmlSecQName2IntegerInfoConstPtr info, xmlNodePtr node, int* intValue) {
+ xmlChar* content = NULL;
+ int ret;
+
+ xmlSecAssert2(info != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(intValue != NULL, -1);
+
+ content = xmlNodeGetContent(node);
+ if(content == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlNodeGetContent",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(node->name));
+ return(-1);
+ }
+
+ ret = xmlSecQName2IntegerGetIntegerFromString(info, node, content, intValue);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecQName2IntegerGetIntegerFromString",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s,value=%s",
+ xmlSecErrorsSafeString(node->name),
+ xmlSecErrorsSafeString(content));
+ xmlFree(content);
+ return(-1);
+ }
+
+ xmlFree(content);
+ return(0);
+}
+
+/**
+ * xmlSecQName2IntegerNodeWrite:
+ * @info: the qname<->integer mapping information.
+ * @node: the parent node.
+ * @nodeName: the child node name.
+ * @nodeNs: the child node namespace.
+ * @intValue: the integer value.
+ *
+ * Creates new child node in @node and sets its value to @intValue.
+ *
+ * Returns 0 on success or a negative value if an error occurs,
+ */
+EXPORT_C
+int
+xmlSecQName2IntegerNodeWrite(xmlSecQName2IntegerInfoConstPtr info, xmlNodePtr node,
+ const xmlChar* nodeName, const xmlChar* nodeNs, int intValue) {
+ xmlNodePtr cur;
+ xmlChar* qname = NULL;
+
+ xmlSecAssert2(info != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(nodeName != NULL, -1);
+
+ /* find and build qname */
+ qname = xmlSecQName2IntegerGetStringFromInteger(info, node, intValue);
+ if(qname == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecQName2IntegerGetStringFromInteger",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s,intValue=%d",
+ xmlSecErrorsSafeString(node->name),
+ intValue);
+ return(-1);
+ }
+
+ cur = xmlSecAddChild(node, nodeName, nodeNs);
+ if(cur == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecAddChild",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s,intValue=%d",
+ xmlSecErrorsSafeString(nodeName),
+ intValue);
+ xmlFree(qname);
+ return(-1);
+ }
+
+ xmlNodeSetContent(cur, qname);
+ xmlFree(qname);
+ return(0);
+}
+
+/**
+ * xmlSecQName2IntegerAttributeRead:
+ * @info: the qname<->integer mapping information.
+ * @node: the element node.
+ * @attrName: the attribute name.
+ * @intValue: the pointer to result integer value.
+ *
+ * Gets the value of @attrName atrtibute from @node and converts it to integer
+ * according to @info.
+ *
+ * Returns 0 on success or a negative value if an error occurs,
+ */
+EXPORT_C
+int
+xmlSecQName2IntegerAttributeRead(xmlSecQName2IntegerInfoConstPtr info, xmlNodePtr node,
+ const xmlChar* attrName, int* intValue) {
+ xmlChar* attrValue;
+ int ret;
+
+ xmlSecAssert2(info != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(attrName != NULL, -1);
+ xmlSecAssert2(intValue != NULL, -1);
+
+ attrValue = xmlGetProp(node, attrName);
+ if(attrValue == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlGetProp",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ "node=%s,attrValue=%s",
+ xmlSecErrorsSafeString(node->name),
+ xmlSecErrorsSafeString(attrName));
+ return(-1);
+ }
+
+ ret = xmlSecQName2IntegerGetIntegerFromString(info, node, attrValue, intValue);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecQName2IntegerGetIntegerFromString",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s,attrName=%s,attrValue=%s",
+ xmlSecErrorsSafeString(node->name),
+ xmlSecErrorsSafeString(attrName),
+ xmlSecErrorsSafeString(attrValue));
+ xmlFree(attrValue);
+ return(-1);
+ }
+
+ xmlFree(attrValue);
+ return(0);
+}
+
+/**
+ * xmlSecQName2IntegerAttributeWrite:
+ * @info: the qname<->integer mapping information.
+ * @node: the parent node.
+ * @attrName: the name of attribute.
+ * @intValue: the integer value.
+ *
+ * Converts @intValue to a qname and sets it to the value of
+ * attribute @attrName in @node.
+ *
+ * Returns 0 on success or a negative value if an error occurs,
+ */
+EXPORT_C
+int
+xmlSecQName2IntegerAttributeWrite(xmlSecQName2IntegerInfoConstPtr info, xmlNodePtr node,
+ const xmlChar* attrName, int intValue) {
+ xmlChar* qname;
+ xmlAttrPtr attr;
+
+ xmlSecAssert2(info != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(attrName != NULL, -1);
+
+ /* find and build qname */
+ qname = xmlSecQName2IntegerGetStringFromInteger(info, node, intValue);
+ if(qname == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecQName2IntegerGetStringFromInteger",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s,attrName=%s,intValue=%d",
+ xmlSecErrorsSafeString(node->name),
+ xmlSecErrorsSafeString(attrName),
+ intValue);
+ return(-1);
+ }
+
+ attr = xmlSetProp(node, attrName, qname);
+ if(attr == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecAddChildNode",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s,attrName=%s,intValue=%d",
+ xmlSecErrorsSafeString(node->name),
+ xmlSecErrorsSafeString(attrName),
+ intValue);
+ xmlFree(qname);
+ return(-1);
+ }
+
+ xmlFree(qname);
+ return(0);
+}
+
+/**
+ * xmlSecQName2IntegerDebugDump:
+ * @info: the qname<->integer mapping information.
+ * @intValue: the integer value.
+ * @output: the pointer to output FILE.
+ *
+ * Prints @intValue into @output.
+ */
+EXPORT_C
+void
+xmlSecQName2IntegerDebugDump(xmlSecQName2IntegerInfoConstPtr info, int intValue,
+ const xmlChar* name, FILE* output) {
+ xmlSecQName2IntegerInfoConstPtr qnameInfo;
+
+ xmlSecAssert(info != NULL);
+ xmlSecAssert(name != NULL);
+ xmlSecAssert(output != NULL);
+
+ qnameInfo = xmlSecQName2IntegerGetInfo(info, intValue);
+ if(qnameInfo != NULL) {
+ fprintf(output, "== %s: %d (name=\"%s\", href=\"%s\")\n", name, intValue,
+ (qnameInfo->qnameLocalPart) ? qnameInfo->qnameLocalPart : BAD_CAST NULL,
+ (qnameInfo->qnameHref) ? qnameInfo->qnameHref : BAD_CAST NULL);
+ }
+}
+
+/**
+ * xmlSecQName2IntegerDebugXmlDump:
+ * @info: the qname<->integer mapping information.
+ * @intValue: the integer value.
+ * @output: the pointer to output FILE.
+ *
+ * Prints @intValue into @output in XML format.
+ */
+EXPORT_C
+void
+xmlSecQName2IntegerDebugXmlDump(xmlSecQName2IntegerInfoConstPtr info, int intValue,
+ const xmlChar* name, FILE* output) {
+ xmlSecQName2IntegerInfoConstPtr qnameInfo;
+
+ xmlSecAssert(info != NULL);
+ xmlSecAssert(name != NULL);
+ xmlSecAssert(output != NULL);
+
+ qnameInfo = xmlSecQName2IntegerGetInfo(info, intValue);
+ if(qnameInfo != NULL) {
+ fprintf(output, "<%s value=\"%d\" href=\"%s\">%s<%s>\n", name, intValue,
+ (qnameInfo->qnameHref) ? qnameInfo->qnameHref : BAD_CAST NULL,
+ (qnameInfo->qnameLocalPart) ? qnameInfo->qnameLocalPart : BAD_CAST NULL,
+ name);
+ }
+}
+
+
+/*************************************************************************
+ *
+ * QName <-> Bits mask mapping
+ *
+ ************************************************************************/
+/**
+ * xmlSecQName2BitMaskGetInfo:
+ * @info: the qname<->bit mask mapping information.
+ * @mask: the bit mask.
+ *
+ * Converts @mask to qname.
+ *
+ * Returns pointer to the qname info for @mask or NULL if mask is unknown.
+ */
+EXPORT_C
+xmlSecQName2BitMaskInfoConstPtr
+xmlSecQName2BitMaskGetInfo(xmlSecQName2BitMaskInfoConstPtr info, xmlSecBitMask mask) {
+ unsigned int ii;
+
+ xmlSecAssert2(info != NULL, NULL);
+
+ for(ii = 0; info[ii].qnameLocalPart != NULL; ii++) {
+ xmlSecAssert2(info[ii].mask != 0, NULL);
+ if(info[ii].mask == mask) {
+ return(&info[ii]);
+ }
+ }
+
+ return(NULL);
+}
+
+/**
+ * xmlSecQName2BitMaskGetBitMask:
+ * @info: the qname<->bit mask mapping information.
+ * @qnameHref: the qname Href value.
+ * @qnameLocalPart: the qname LocalPart value.
+ * @mask: the pointer to result mask.
+ *
+ * Converts @qnameLocalPart to @mask.
+ *
+ * Returns 0 on success or a negative value if an error occurs,
+ */
+EXPORT_C
+int
+xmlSecQName2BitMaskGetBitMask(xmlSecQName2BitMaskInfoConstPtr info,
+ const xmlChar* qnameHref, const xmlChar* qnameLocalPart,
+ xmlSecBitMask* mask) {
+ unsigned int ii;
+
+ xmlSecAssert2(info != NULL, -1);
+ xmlSecAssert2(qnameLocalPart != NULL, -1);
+ xmlSecAssert2(mask != NULL, -1);
+
+ for(ii = 0; info[ii].qnameLocalPart != NULL; ii++) {
+ xmlSecAssert2(info[ii].mask != 0, -1);
+ if(xmlStrEqual(info[ii].qnameLocalPart, qnameLocalPart) &&
+ xmlStrEqual(info[ii].qnameHref, qnameHref)) {
+
+ (*mask) = info[ii].mask;
+ return(0);
+ }
+ }
+
+ return(-1);
+}
+
+/**
+ * xmlSecQName2BitMaskGetBitMaskFromBitMask:
+ * @info: the qname<->integer mapping information.
+ * @node: the pointer to node.
+ * @qname: the qname string.
+ * @mask: the pointer to result msk value.
+ *
+ * Converts @qname into integer in context of @node.
+ *
+ * Returns 0 on success or a negative value if an error occurs,
+ */
+EXPORT_C
+int
+xmlSecQName2BitMaskGetBitMaskFromString(xmlSecQName2BitMaskInfoConstPtr info,
+ xmlNodePtr node, const xmlChar* qname,
+ xmlSecBitMask* mask) {
+ const xmlChar* qnameLocalPart = NULL;
+ xmlChar* qnamePrefix = NULL;
+ const xmlChar* qnameHref;
+ xmlNsPtr ns;
+ int ret;
+
+ xmlSecAssert2(info != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(qname != NULL, -1);
+ xmlSecAssert2(mask != NULL, -1);
+
+ qnameLocalPart = xmlStrchr(qname, ':');
+ if(qnameLocalPart != NULL) {
+ qnamePrefix = xmlStrndup(qname, qnameLocalPart - qname);
+ if(qnamePrefix == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlStrndup",
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ "node=%s,value=%s",
+ xmlSecErrorsSafeString(node->name),
+ xmlSecErrorsSafeString(qname));
+ return(-1);
+ }
+ qnameLocalPart++;
+ } else {
+ qnamePrefix = NULL;
+ qnameLocalPart = qname;
+ }
+
+ /* search namespace href */
+ ns = xmlSearchNs(node->doc, node, qnamePrefix);
+ if((ns == NULL) && (qnamePrefix != NULL)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSearchNs",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ "node=%s,qnamePrefix=%s",
+ xmlSecErrorsSafeString(node->name),
+ xmlSecErrorsSafeString(qnamePrefix));
+ if(qnamePrefix != NULL) {
+ xmlFree(qnamePrefix);
+ }
+ return(-1);
+ }
+ qnameHref = (ns != NULL) ? ns->href : BAD_CAST NULL;
+
+ /* and finally search for integer */
+ ret = xmlSecQName2BitMaskGetBitMask(info, qnameHref, qnameLocalPart, mask);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecQName2BitMaskGetBitMask",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s,qnameLocalPart=%s,qnameHref=%s",
+ xmlSecErrorsSafeString(node->name),
+ xmlSecErrorsSafeString(qnameLocalPart),
+ xmlSecErrorsSafeString(qnameHref));
+ if(qnamePrefix != NULL) {
+ xmlFree(qnamePrefix);
+ }
+ return(-1);
+ }
+
+ if(qnamePrefix != NULL) {
+ xmlFree(qnamePrefix);
+ }
+ return(0);
+}
+
+
+/**
+ * xmlSecQName2BitMaskGetStringFromBitMask:
+ * @info: the qname<->integer mapping information.
+ * @node: the pointer to node.
+ * @mask: the mask.
+ *
+ * Creates qname string for @mask in context of given @node. Caller
+ * is responsible for freeing returned string with @xmlFree.
+ *
+ * Returns pointer to newly allocated string on success or NULL if an error occurs,
+ */
+EXPORT_C
+xmlChar*
+xmlSecQName2BitMaskGetStringFromBitMask(xmlSecQName2BitMaskInfoConstPtr info,
+ xmlNodePtr node, xmlSecBitMask mask) {
+ xmlSecQName2BitMaskInfoConstPtr qnameInfo;
+
+ xmlSecAssert2(info != NULL, NULL);
+ xmlSecAssert2(node != NULL, NULL);
+
+ qnameInfo = xmlSecQName2BitMaskGetInfo(info, mask);
+ if(qnameInfo == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecQName2BitMaskGetInfo",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s,mask=%d",
+ xmlSecErrorsSafeString(node->name),
+ mask);
+ return(NULL);
+ }
+
+ return(xmlSecGetQName(node, qnameInfo->qnameHref, qnameInfo->qnameLocalPart));
+}
+
+/**
+ * xmlSecQName2BitMaskNodesRead:
+ * @info: the qname<->bit mask mapping information.
+ * @node: the start.
+ * @nodeName: the mask nodes name.
+ * @nodeNs: the mask nodes namespace.
+ * @stopOnUnknown: if this flag is set then function exits if unknown
+ * value was found.
+ * @mask: the pointer to result mask.
+ *
+ * Reads <@nodeNs:@nodeName> elements and puts the result bit mask
+ * into @mask. When function exits, @node points to the first element node
+ * after all the <@nodeNs:@nodeName> elements.
+ *
+ * Returns 0 on success or a negative value if an error occurs,
+ */
+EXPORT_C
+int
+xmlSecQName2BitMaskNodesRead(xmlSecQName2BitMaskInfoConstPtr info, xmlNodePtr* node,
+ const xmlChar* nodeName, const xmlChar* nodeNs,
+ int stopOnUnknown, xmlSecBitMask* mask) {
+ xmlNodePtr cur;
+ xmlChar* content;
+ xmlSecBitMask tmp;
+ int ret;
+
+ xmlSecAssert2(info != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(mask != NULL, -1);
+
+ (*mask) = 0;
+ cur = (*node);
+ while((cur != NULL) && (xmlSecCheckNodeName(cur, nodeName, nodeNs))) {
+ content = xmlNodeGetContent(cur);
+ if(content == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlNodeGetContent",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(cur->name));
+ return(-1);
+ }
+
+ ret = xmlSecQName2BitMaskGetBitMaskFromString(info, cur, content, &tmp);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecQName2BitMaskGetBitMaskFromString",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "value=%s",
+ xmlSecErrorsSafeString(content));
+ xmlFree(content);
+ return(-1);
+ }
+ xmlFree(content);
+
+ if((stopOnUnknown != 0) && (tmp == 0)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecQName2BitMaskGetBitMaskFromString",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "value=%s",
+ xmlSecErrorsSafeString(content));
+ return(-1);
+ }
+
+ (*mask) |= tmp;
+ cur = xmlSecGetNextElementNode(cur->next);
+ }
+
+ (*node) = cur;
+ return(0);
+}
+
+/**
+ * xmlSecQName2BitMaskNodesWrite:
+ * @info: the qname<->bit mask mapping information.
+ * @node: the parent element for mask nodes.
+ * @nodeName: the mask nodes name.
+ * @nodeNs: the mask nodes namespace.
+ * @mask: the bit mask.
+ *
+ * Writes <@nodeNs:@nodeName> elemnts with values from @mask to @node.
+ *
+ * Returns 0 on success or a negative value if an error occurs,
+ */
+EXPORT_C
+int
+xmlSecQName2BitMaskNodesWrite(xmlSecQName2BitMaskInfoConstPtr info, xmlNodePtr node,
+ const xmlChar* nodeName, const xmlChar* nodeNs,
+ xmlSecBitMask mask) {
+ unsigned int ii;
+
+ xmlSecAssert2(info != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(nodeName != NULL, -1);
+
+ for(ii = 0; (mask != 0) && (info[ii].qnameLocalPart != NULL); ii++) {
+ xmlSecAssert2(info[ii].mask != 0, -1);
+
+ if((mask & info[ii].mask) != 0) {
+ xmlNodePtr cur;
+ xmlChar* qname;
+
+ qname = xmlSecGetQName(node, info[ii].qnameHref, info[ii].qnameLocalPart);
+ if(qname == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecGetQName",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(nodeName));
+ return(-1);
+ }
+
+ cur = xmlSecAddChild(node, nodeName, nodeNs);
+ if(cur == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecAddChild",
+ XMLSEC_ERRORS_R_XML_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(nodeName));
+ xmlFree(qname);
+ return(-1);
+ }
+
+ xmlNodeSetContent(cur, qname);
+ xmlFree(qname);
+ }
+ }
+ return(0);
+}
+
+/**
+ * xmlSecQName2BitMaskDebugDump:
+ * @info: the qname<->bit mask mapping information.
+ * @mask: the bit mask.
+ * @output: the pointer to output FILE.
+ *
+ * Prints debug information about @mask to @output.
+ */
+EXPORT_C
+void
+xmlSecQName2BitMaskDebugDump(xmlSecQName2BitMaskInfoConstPtr info, xmlSecBitMask mask,
+ const xmlChar* name, FILE* output) {
+ unsigned int ii;
+
+ xmlSecAssert(info != NULL);
+ xmlSecAssert(name != NULL);
+ xmlSecAssert(output != NULL);
+
+ if(mask == 0) {
+ return;
+ }
+
+ fprintf(output, "== %s (0x%08x): ", name, mask);
+ for(ii = 0; (mask != 0) && (info[ii].qnameLocalPart != NULL); ii++) {
+ xmlSecAssert(info[ii].mask != 0);
+
+ if((mask & info[ii].mask) != 0) {
+ fprintf(output, "name=\"%s\" (href=\"%s\"),", info[ii].qnameLocalPart, info[ii].qnameHref);
+ }
+ }
+ fprintf(output, "\n");
+}
+
+/**
+ * xmlSecQName2BitMaskDebugXmlDump:
+ * @info: the qname<->bit mask mapping information.
+ * @mask: the bit mask.
+ * @output: the pointer to output FILE.
+ *
+ * Prints debug information about @mask to @output in XML format.
+ */
+EXPORT_C
+void
+xmlSecQName2BitMaskDebugXmlDump(xmlSecQName2BitMaskInfoConstPtr info, xmlSecBitMask mask,
+ const xmlChar* name, FILE* output) {
+ unsigned int ii;
+
+ xmlSecAssert(info != NULL);
+ xmlSecAssert(name != NULL);
+ xmlSecAssert(output != NULL);
+
+ if(mask == 0) {
+ return;
+ }
+
+ fprintf(output, "<%sList>\n", name);
+ for(ii = 0; (mask != 0) && (info[ii].qnameLocalPart != NULL); ii++) {
+ xmlSecAssert(info[ii].mask != 0);
+
+ if((mask & info[ii].mask) != 0) {
+ fprintf(output, "<%s href=\"%s\">%s</%s>\n", name,
+ info[ii].qnameHref, info[ii].qnameLocalPart, name);
+ }
+ }
+ fprintf(output, "</%sList>\n", name);
+}
+
+
+
+