Files
libupnp/ixml/src/element.c
Marcelo Roberto Jimenez 812d019d12 Backport of ixml from 1.8.x.
git-svn-id: https://pupnp.svn.sourceforge.net/svnroot/pupnp/branches/branch-1.6.x@478 119443c7-1b9e-41f8-b6fc-b9c35fce742c
2008-07-27 05:01:52 +00:00

718 lines
16 KiB
C

/*******************************************************************************
*
* Copyright (c) 2000-2003 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************/
/*!
* \file
*/
#include "ixmlparser.h"
#include <assert.h>
#include <stdlib.h> /* for free() */
#include <string.h>
void ixmlElement_init(IXML_Element *element)
{
if (element != NULL) {
memset(element, 0, sizeof (IXML_Element));
}
}
const DOMString ixmlElement_getTagName(IXML_Element *element)
{
if( element != NULL ) {
return element->tagName;
} else {
return NULL;
}
}
int ixmlElement_setTagName(IXML_Element *element, const char *tagName)
{
int rc = IXML_SUCCESS;
assert(element != NULL && tagName != NULL);
if (element == NULL || tagName == NULL) {
return IXML_FAILED;
}
if (element->tagName != NULL) {
free(element->tagName);
}
element->tagName = strdup(tagName);
if (element->tagName == NULL) {
rc = IXML_INSUFFICIENT_MEMORY;
}
return rc;
}
const DOMString ixmlElement_getAttribute(IXML_Element *element, const DOMString name)
{
IXML_Node *attrNode;
if (element == NULL || name == NULL) {
return NULL;
}
attrNode = element->n.firstAttr;
while (attrNode != NULL) {
if (strcmp(attrNode->nodeName, name) == 0) {
return attrNode->nodeValue;
} else {
attrNode = attrNode->nextSibling;
}
}
return NULL;
}
int ixmlElement_setAttribute(
IXML_Element *element,
const DOMString name,
const DOMString value)
{
IXML_Node *attrNode;
IXML_Attr *newAttrNode;
short errCode = IXML_SUCCESS;
if (element == NULL || name == NULL || value == NULL) {
errCode = IXML_INVALID_PARAMETER;
goto ErrorHandler;
}
if (Parser_isValidXmlName(name) == FALSE) {
errCode = IXML_INVALID_CHARACTER_ERR;
goto ErrorHandler;
}
attrNode = element->n.firstAttr;
while (attrNode != NULL) {
if (strcmp(attrNode->nodeName, name) == 0) {
/* Found it */
break;
} else {
attrNode = attrNode->nextSibling;
}
}
if (attrNode == NULL) {
/* Add a new attribute */
errCode = ixmlDocument_createAttributeEx(
(IXML_Document *)element->n.ownerDocument, name, &newAttrNode);
if (errCode != IXML_SUCCESS) {
goto ErrorHandler;
}
attrNode = (IXML_Node *)newAttrNode;
attrNode->nodeValue = strdup(value);
if (attrNode->nodeValue == NULL) {
ixmlAttr_free(newAttrNode);
errCode = IXML_INSUFFICIENT_MEMORY;
goto ErrorHandler;
}
errCode = ixmlElement_setAttributeNode(element, newAttrNode, NULL);
if (errCode != IXML_SUCCESS) {
ixmlAttr_free(newAttrNode);
goto ErrorHandler;
}
} else {
if (attrNode->nodeValue != NULL) {
/* Attribute name has a value already */
free(attrNode->nodeValue);
}
attrNode->nodeValue = strdup(value);
if (attrNode->nodeValue == NULL) {
errCode = IXML_INSUFFICIENT_MEMORY;
}
}
ErrorHandler:
return errCode;
}
int ixmlElement_removeAttribute(IXML_Element *element, const DOMString name)
{
IXML_Node *attrNode;
if (element == NULL || name == NULL) {
return IXML_INVALID_PARAMETER;
}
attrNode = element->n.firstAttr;
while (attrNode != NULL) {
if (strcmp(attrNode->nodeName, name) == 0) {
/* Found it */
break;
} else {
attrNode = attrNode->nextSibling;
}
}
if (attrNode != NULL) {
/* Has the attribute */
if (attrNode->nodeValue != NULL) {
free(attrNode->nodeValue);
attrNode->nodeValue = NULL;
}
}
return IXML_SUCCESS;
}
IXML_Attr *ixmlElement_getAttributeNode(IXML_Element *element, const DOMString name)
{
IXML_Node *attrNode;
if (element == NULL || name == NULL) {
return NULL;
}
attrNode = element->n.firstAttr;
while (attrNode != NULL) {
if (strcmp(attrNode->nodeName, name) == 0) { // found it
break;
} else {
attrNode = attrNode->nextSibling;
}
}
return (IXML_Attr *)attrNode;
}
int ixmlElement_setAttributeNode(
IXML_Element *element,
IXML_Attr *newAttr,
IXML_Attr **rtAttr)
{
IXML_Node *attrNode = NULL;
IXML_Node *node = NULL;
IXML_Node *nextAttr = NULL;
IXML_Node *prevAttr = NULL;
IXML_Node *preSib = NULL;
IXML_Node *nextSib = NULL;
if (element == NULL || newAttr == NULL) {
return IXML_INVALID_PARAMETER;
}
if (newAttr->n.ownerDocument != element->n.ownerDocument) {
return IXML_WRONG_DOCUMENT_ERR;
}
if (newAttr->ownerElement != NULL) {
return IXML_INUSE_ATTRIBUTE_ERR;
}
newAttr->ownerElement = element;
node = (IXML_Node *)newAttr;
attrNode = element->n.firstAttr;
while (attrNode != NULL) {
if (strcmp(attrNode->nodeName, node->nodeName) == 0) {
/* Found it */
break;
} else {
attrNode = attrNode->nextSibling;
}
}
if (attrNode != NULL) {
/* Already present, will replace by newAttr */
preSib = attrNode->prevSibling;
nextSib = attrNode->nextSibling;
if (preSib != NULL) {
preSib->nextSibling = node;
}
if (nextSib != NULL) {
nextSib->prevSibling = node;
}
if (element->n.firstAttr == attrNode) {
element->n.firstAttr = node;
}
if (rtAttr != NULL) {
*rtAttr = (IXML_Attr *)attrNode;
}
} else {
/* Add this attribute */
if (element->n.firstAttr != NULL) {
prevAttr = element->n.firstAttr;
nextAttr = prevAttr->nextSibling;
while (nextAttr != NULL) {
prevAttr = nextAttr;
nextAttr = prevAttr->nextSibling;
}
prevAttr->nextSibling = node;
node->prevSibling = prevAttr;
} else {
/* This is the first attribute node */
element->n.firstAttr = node;
node->prevSibling = NULL;
node->nextSibling = NULL;
}
if (rtAttr != NULL) {
*rtAttr = NULL;
}
}
return IXML_SUCCESS;
}
/*!
* \brief Find a attribute node whose contents are the same as the oldAttr.
*
* \return If found, the attribute node is returned, otherwise \b NULL is
* returned.
*/
static IXML_Node *ixmlElement_findAttributeNode(
/*! [in] The element to search for the attribute. */
IXML_Element *element,
/*! [in] The attribute node to match. */
IXML_Attr *oldAttr)
{
IXML_Node *attrNode;
IXML_Node *oldAttrNode = (IXML_Node *)oldAttr;
assert(element != NULL && oldAttr != NULL);
attrNode = element->n.firstAttr;
while (attrNode != NULL) {
/* parentNode, prevSib, nextSib and ownerDocument doesn't matter */
if (ixmlNode_compare(attrNode, oldAttrNode) == TRUE) {
/* Found it */
break;
} else {
attrNode = attrNode->nextSibling;
}
}
return attrNode;
}
int ixmlElement_removeAttributeNode(
IXML_Element *element,
IXML_Attr *oldAttr,
IXML_Attr **rtAttr)
{
IXML_Node *attrNode;
IXML_Node *preSib;
IXML_Node *nextSib;
if(element == NULL || oldAttr == NULL) {
return IXML_INVALID_PARAMETER;
}
attrNode = ixmlElement_findAttributeNode( element, oldAttr );
if (attrNode != NULL) {
/* Has the attribute */
preSib = attrNode->prevSibling;
nextSib = attrNode->nextSibling;
if (preSib != NULL) {
preSib->nextSibling = nextSib;
}
if (nextSib != NULL) {
nextSib->prevSibling = preSib;
}
if (element->n.firstAttr == attrNode) {
element->n.firstAttr = nextSib;
}
attrNode->parentNode = NULL;
attrNode->prevSibling = NULL;
attrNode->nextSibling = NULL;
*rtAttr = (IXML_Attr *)attrNode;
return IXML_SUCCESS;
} else {
return IXML_NOT_FOUND_ERR;
}
}
IXML_NodeList *ixmlElement_getElementsByTagName(
IXML_Element *element,
const DOMString tagName)
{
IXML_NodeList *returnNodeList = NULL;
if (element != NULL && tagName != NULL) {
ixmlNode_getElementsByTagName(
(IXML_Node *)element, tagName, &returnNodeList);
}
return returnNodeList;
}
const DOMString ixmlElement_getAttributeNS(
IN IXML_Element *element,
IN const DOMString namespaceURI,
IN const DOMString localName)
{
IXML_Node *attrNode;
if (element == NULL || namespaceURI == NULL || localName == NULL) {
return NULL;
}
attrNode = element->n.firstAttr;
while (attrNode != NULL) {
if (strcmp(attrNode->localName, localName) == 0 &&
strcmp(attrNode->namespaceURI, namespaceURI) == 0) {
/* Found it */
return attrNode->nodeValue;
} else {
attrNode = attrNode->nextSibling;
}
}
return NULL;
}
int ixmlElement_setAttributeNS(
IXML_Element *element,
const DOMString namespaceURI,
const DOMString qualifiedName,
const DOMString value)
{
IXML_Node *attrNode = NULL;
IXML_Node newAttrNode;
IXML_Attr *newAttr;
int rc;
if (element == NULL || namespaceURI == NULL || qualifiedName == NULL ||
value == NULL) {
return IXML_INVALID_PARAMETER;
}
if (Parser_isValidXmlName(qualifiedName) == FALSE) {
return IXML_INVALID_CHARACTER_ERR;
}
ixmlNode_init(&newAttrNode);
newAttrNode.nodeName = strdup(qualifiedName);
if (newAttrNode.nodeName == NULL) {
return IXML_INSUFFICIENT_MEMORY;
}
rc = Parser_setNodePrefixAndLocalName(&newAttrNode);
if (rc != IXML_SUCCESS) {
Parser_freeNodeContent(&newAttrNode);
return rc;
}
/* see DOM 2 spec page 59 */
if ((newAttrNode.prefix != NULL && namespaceURI == NULL) ||
(strcmp(newAttrNode.prefix, "xml") == 0 &&
strcmp(namespaceURI, "http://www.w3.org/XML/1998/namespace") != 0) ||
(strcmp(qualifiedName, "xmlns") == 0 &&
strcmp(namespaceURI, "http://www.w3.org/2000/xmlns/") != 0)) {
Parser_freeNodeContent( &newAttrNode );
return IXML_NAMESPACE_ERR;
}
attrNode = element->n.firstAttr;
while (attrNode != NULL) {
if (strcmp(attrNode->localName, newAttrNode.localName) == 0 &&
strcmp(attrNode->namespaceURI, namespaceURI) == 0) {
/* Found it */
break;
} else {
attrNode = attrNode->nextSibling;
}
}
if (attrNode != NULL) {
if (attrNode->prefix != NULL) {
/* Remove the old prefix */
free(attrNode->prefix);
}
/* replace it with the new prefix */
attrNode->prefix = strdup( newAttrNode.prefix );
if (attrNode->prefix == NULL) {
Parser_freeNodeContent(&newAttrNode);
return IXML_INSUFFICIENT_MEMORY;
}
if (attrNode->nodeValue != NULL) {
free(attrNode->nodeValue);
}
attrNode->nodeValue = strdup(value);
if (attrNode->nodeValue == NULL) {
free(attrNode->prefix);
Parser_freeNodeContent(&newAttrNode);
return IXML_INSUFFICIENT_MEMORY;
}
} else {
/* Add a new attribute */
rc = ixmlDocument_createAttributeNSEx(
(IXML_Document *)element->n.ownerDocument,
namespaceURI,
qualifiedName,
&newAttr);
if (rc != IXML_SUCCESS) {
return rc;
}
newAttr->n.nodeValue = strdup(value);
if (newAttr->n.nodeValue == NULL) {
ixmlAttr_free(newAttr);
return IXML_INSUFFICIENT_MEMORY;
}
if (ixmlElement_setAttributeNodeNS(element, newAttr, NULL) != IXML_SUCCESS) {
ixmlAttr_free(newAttr);
return IXML_FAILED;
}
}
Parser_freeNodeContent(&newAttrNode);
return IXML_SUCCESS;
}
int ixmlElement_removeAttributeNS(
IXML_Element *element,
const DOMString namespaceURI,
const DOMString localName)
{
IXML_Node *attrNode = NULL;
if (element == NULL || namespaceURI == NULL || localName == NULL) {
return IXML_INVALID_PARAMETER;
}
attrNode = element->n.firstAttr;
while (attrNode != NULL) {
if (strcmp(attrNode->localName, localName) == 0 &&
strcmp(attrNode->namespaceURI, namespaceURI) == 0) {
/* Found it */
break;
} else {
attrNode = attrNode->nextSibling;
}
}
if(attrNode != NULL) {
/* Has the attribute */
if(attrNode->nodeValue != NULL) {
free(attrNode->nodeValue);
attrNode->nodeValue = NULL;
}
}
return IXML_SUCCESS;
}
IXML_Attr *ixmlElement_getAttributeNodeNS(
IXML_Element *element,
const DOMString namespaceURI,
const DOMString localName)
{
IXML_Node *attrNode = NULL;
if (element == NULL || namespaceURI == NULL || localName == NULL) {
return NULL;
}
attrNode = element->n.firstAttr;
while (attrNode != NULL) {
if (strcmp(attrNode->localName, localName) == 0 &&
strcmp(attrNode->namespaceURI, namespaceURI) == 0) {
// found it
break;
} else {
attrNode = attrNode->nextSibling;
}
}
return (IXML_Attr *)attrNode;
}
int ixmlElement_setAttributeNodeNS(
IN IXML_Element *element,
IN IXML_Attr *newAttr,
OUT IXML_Attr **rtAttr)
{
IXML_Node *attrNode = NULL;
IXML_Node *node = NULL;
IXML_Node *prevAttr = NULL;
IXML_Node *nextAttr = NULL;
IXML_Node *preSib = NULL;
IXML_Node *nextSib = NULL;
if (element == NULL || newAttr == NULL) {
return IXML_INVALID_PARAMETER;
}
if (newAttr->n.ownerDocument != element->n.ownerDocument) {
return IXML_WRONG_DOCUMENT_ERR;
}
if (newAttr->ownerElement != NULL && newAttr->ownerElement != element) {
return IXML_INUSE_ATTRIBUTE_ERR;
}
newAttr->ownerElement = element;
node = (IXML_Node *)newAttr;
attrNode = element->n.firstAttr;
while (attrNode != NULL) {
if (strcmp(attrNode->localName, node->localName) == 0 &&
strcmp(attrNode->namespaceURI, node->namespaceURI) == 0) {
/* Found it */
break;
} else {
attrNode = attrNode->nextSibling;
}
}
if (attrNode != NULL) {
/* already present, will replace by newAttr */
preSib = attrNode->prevSibling;
nextSib = attrNode->nextSibling;
if (preSib != NULL) {
preSib->nextSibling = node;
}
if (nextSib != NULL) {
nextSib->prevSibling = node;
}
if (element->n.firstAttr == attrNode) {
element->n.firstAttr = node;
}
*rtAttr = (IXML_Attr *)attrNode;
} else {
/* Add this attribute */
if (element->n.firstAttr != NULL) {
/* Element has attribute already */
prevAttr = element->n.firstAttr;
nextAttr = prevAttr->nextSibling;
while (nextAttr != NULL) {
prevAttr = nextAttr;
nextAttr = prevAttr->nextSibling;
}
prevAttr->nextSibling = node;
} else {
/* This is the first attribute node */
element->n.firstAttr = node;
node->prevSibling = NULL;
node->nextSibling = NULL;
}
if (rtAttr != NULL) {
*rtAttr = NULL;
}
}
return IXML_SUCCESS;
}
IXML_NodeList *ixmlElement_getElementsByTagNameNS(
IXML_Element *element,
const DOMString namespaceURI,
const DOMString localName)
{
IXML_Node *node = (IXML_Node *)element;
IXML_NodeList *nodeList = NULL;
if(element != NULL && namespaceURI != NULL && localName != NULL) {
ixmlNode_getElementsByTagNameNS(
node, namespaceURI, localName, &nodeList);
}
return nodeList;
}
BOOL ixmlElement_hasAttribute(
IXML_Element *element,
const DOMString name)
{
IXML_Node *attrNode = NULL;
if (element == NULL || name == NULL) {
return FALSE;
}
attrNode = element->n.firstAttr;
while (attrNode != NULL) {
if (strcmp(attrNode->nodeName, name) == 0) {
return TRUE;
} else {
attrNode = attrNode->nextSibling;
}
}
return FALSE;
}
BOOL ixmlElement_hasAttributeNS(
IXML_Element * element,
const DOMString namespaceURI,
const DOMString localName )
{
IXML_Node *attrNode = NULL;
if (element == NULL || namespaceURI == NULL || localName == NULL) {
return FALSE;
}
attrNode = element->n.firstAttr;
while (attrNode != NULL) {
if (strcmp(attrNode->localName, localName) == 0 &&
strcmp(attrNode->namespaceURI, namespaceURI) == 0) {
return TRUE;
} else {
attrNode = attrNode->nextSibling;
}
}
return FALSE;
}
void ixmlElement_free(IXML_Element *element)
{
if (element != NULL) {
ixmlNode_free((IXML_Node *)element);
}
}