diff -r 000000000000 -r e35f40988205 xmlsecurityengine/xmlsec/src/xmlsec_xmltree.c --- /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 + * Portion Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. + */ +#include "xmlsec_globals.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#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\n", name, + info[ii].qnameHref, info[ii].qnameLocalPart, name); + } + } + fprintf(output, "\n", name); +} + + + +