blob: 3d9f3635b0a30a498a929ed1fc18d86a177aedcf [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* $Id: DOMAttrMapImpl.cpp 568078 2007-08-21 11:43:25Z amassari $
*/
#include "DOMAttrMapImpl.hpp"
#include "DOMAttrImpl.hpp"
#include "DOMNodeImpl.hpp"
#include "DOMElementImpl.hpp"
#include "DOMCasts.hpp"
#include "DOMNodeVector.hpp"
#include <xercesc/dom/DOMAttr.hpp>
#include <xercesc/dom/DOMException.hpp>
XERCES_CPP_NAMESPACE_BEGIN
DOMAttrMapImpl::DOMAttrMapImpl(DOMNode *ownerNod)
{
this->fOwnerNode=ownerNod;
this->fNodes = 0;
hasDefaults(false);
}
DOMAttrMapImpl::DOMAttrMapImpl(DOMNode *ownerNod, const DOMAttrMapImpl *defaults)
{
this->fOwnerNode=ownerNod;
this->fNodes = 0;
hasDefaults(false);
if (defaults != 0)
{
if (defaults->getLength() > 0)
{
hasDefaults(true);
cloneContent(defaults);
}
}
}
DOMAttrMapImpl::~DOMAttrMapImpl()
{
}
void DOMAttrMapImpl::cloneContent(const DOMAttrMapImpl *srcmap)
{
if ((srcmap != 0) && (srcmap->fNodes != 0))
{
if (fNodes != 0)
fNodes->reset();
else
{
XMLSize_t size = srcmap->fNodes->size();
if(size > 0) {
DOMDocument *doc = fOwnerNode->getOwnerDocument();
fNodes = new (doc) DOMNodeVector(doc, size);
}
}
for (XMLSize_t i = 0; i < srcmap->fNodes->size(); i++)
{
DOMNode *n = srcmap->fNodes->elementAt(i);
DOMNode *clone = n->cloneNode(true);
castToNodeImpl(clone)->isSpecified(castToNodeImpl(n)->isSpecified());
castToNodeImpl(clone)->fOwnerNode = fOwnerNode;
castToNodeImpl(clone)->isOwned(true);
fNodes->addElement(clone);
}
}
}
DOMAttrMapImpl *DOMAttrMapImpl::cloneAttrMap(DOMNode *ownerNode_p)
{
DOMAttrMapImpl *newmap = new (castToNodeImpl(ownerNode_p)->getOwnerDocument()) DOMAttrMapImpl(ownerNode_p);
newmap->cloneContent(this);
// newmap->attrDefaults = this->attrDefaults; // revisit
return newmap;
}
void DOMAttrMapImpl::setReadOnly(bool readOnl, bool deep)
{
// this->fReadOnly=readOnl;
if(deep && fNodes!=0)
{
int sz = fNodes->size();
for (int i=0; i<sz; ++i) {
castToNodeImpl(fNodes->elementAt(i))->setReadOnly(readOnl, deep);
}
}
}
bool DOMAttrMapImpl::readOnly() {
return castToNodeImpl(fOwnerNode)->isReadOnly();
}
int DOMAttrMapImpl::findNamePoint(const XMLCh *name) const
{
// Binary search
int i=0;
if(fNodes!=0)
{
int first=0,last=fNodes->size()-1;
while(first<=last)
{
i=(first+last)/2;
int test = XMLString::compareString(name, fNodes->elementAt(i)->getNodeName());
if(test==0)
return i; // Name found
else if(test<0)
last=i-1;
else
first=i+1;
}
if(first>i) i=first;
}
/********************
// Linear search
int i = 0;
if (fNodes != 0)
for (i = 0; i < fNodes.size(); ++i)
{
int test = name.compareTo(((NodeImpl *) (fNodes.elementAt(i))).getNodeName());
if (test == 0)
return i;
else
if (test < 0)
{
break; // Found insertpoint
}
}
*******************/
return -1 - i; // not-found has to be encoded.
}
DOMNode * DOMAttrMapImpl::getNamedItem(const XMLCh *name) const
{
int i=findNamePoint(name);
return (i<0) ? 0 : fNodes->elementAt(i);
}
DOMNode *DOMAttrMapImpl::setNamedItem(DOMNode *arg)
{
if (arg->getNodeType() != DOMNode::ATTRIBUTE_NODE)
throw DOMException(DOMException::HIERARCHY_REQUEST_ERR, 0, GetDOMNamedNodeMapMemoryManager);
DOMDocument *doc = fOwnerNode->getOwnerDocument();
DOMNodeImpl *argImpl = castToNodeImpl(arg);
if(argImpl->getOwnerDocument() != doc)
throw DOMException(DOMException::WRONG_DOCUMENT_ERR, 0, GetDOMNamedNodeMapMemoryManager);
if (this->readOnly())
throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNamedNodeMapMemoryManager);
if ((arg->getNodeType() == DOMNode::ATTRIBUTE_NODE) && argImpl->isOwned() && (argImpl->fOwnerNode != fOwnerNode))
throw DOMException(DOMException::INUSE_ATTRIBUTE_ERR,0, GetDOMNamedNodeMapMemoryManager);
argImpl->fOwnerNode = fOwnerNode;
argImpl->isOwned(true);
int i=findNamePoint(arg->getNodeName());
DOMNode * previous=0;
if(i>=0)
{
previous = fNodes->elementAt(i);
fNodes->setElementAt(arg,i);
}
else
{
i=-1-i; // Insert point (may be end of list)
if(0==fNodes)
{
fNodes=new (doc) DOMNodeVector(doc);
}
fNodes->insertElementAt(arg,i);
}
if (previous != 0) {
castToNodeImpl(previous)->fOwnerNode = fOwnerNode->getOwnerDocument();
castToNodeImpl(previous)->isOwned(false);
}
return previous;
}
//Introduced in DOM Level 2
int DOMAttrMapImpl::findNamePoint(const XMLCh *namespaceURI,
const XMLCh *localName) const
{
if (fNodes == 0)
return -1;
// This is a linear search through the same fNodes Vector.
// The Vector is sorted on the DOM Level 1 nodename.
// The DOM Level 2 NS keys are namespaceURI and Localname,
// so we must linear search thru it.
// In addition, to get this to work with fNodes without any namespace
// (namespaceURI and localNames are both 0) we then use the nodeName
// as a secondary key.
int i, len = fNodes -> size();
for (i = 0; i < len; ++i) {
DOMNode *node = fNodes -> elementAt(i);
const XMLCh * nNamespaceURI = node->getNamespaceURI();
const XMLCh * nLocalName = node->getLocalName();
if (!XMLString::equals(nNamespaceURI, namespaceURI)) //URI not match
continue;
else {
if (XMLString::equals(localName, nLocalName)
||
(nLocalName == 0 && XMLString::equals(localName, node->getNodeName())))
return i;
}
}
return -1; //not found
}
DOMNode *DOMAttrMapImpl::getNamedItemNS(const XMLCh *namespaceURI,
const XMLCh *localName) const
{
int i = findNamePoint(namespaceURI, localName);
return i < 0 ? 0 : fNodes -> elementAt(i);
}
DOMNode *DOMAttrMapImpl::setNamedItemNS(DOMNode* arg)
{
if (arg->getNodeType() != DOMNode::ATTRIBUTE_NODE)
throw DOMException(DOMException::HIERARCHY_REQUEST_ERR, 0, GetDOMNamedNodeMapMemoryManager);
DOMDocument *doc = fOwnerNode->getOwnerDocument();
DOMNodeImpl *argImpl = castToNodeImpl(arg);
if (argImpl->getOwnerDocument() != doc)
throw DOMException(DOMException::WRONG_DOCUMENT_ERR,0, GetDOMNamedNodeMapMemoryManager);
if (this->readOnly())
throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNamedNodeMapMemoryManager);
if (argImpl->isOwned())
throw DOMException(DOMException::INUSE_ATTRIBUTE_ERR,0, GetDOMNamedNodeMapMemoryManager);
argImpl->fOwnerNode = fOwnerNode;
argImpl->isOwned(true);
int i=findNamePoint(arg->getNamespaceURI(), arg->getLocalName());
DOMNode *previous=0;
if(i>=0) {
previous = fNodes->elementAt(i);
fNodes->setElementAt(arg,i);
} else {
i=findNamePoint(arg->getNodeName()); // Insert point (may be end of list)
if (i<0)
i = -1 - i;
if(0==fNodes)
fNodes=new (doc) DOMNodeVector(doc);
fNodes->insertElementAt(arg,i);
}
if (previous != 0) {
castToNodeImpl(previous)->fOwnerNode = fOwnerNode->getOwnerDocument();
castToNodeImpl(previous)->isOwned(false);
}
return previous;
}
DOMNode *DOMAttrMapImpl::removeNamedItem(const XMLCh *name)
{
if (this->readOnly())
throw DOMException(
DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNamedNodeMapMemoryManager);
int i=findNamePoint(name);
DOMNode *removed = 0;
if(i<0)
throw DOMException(DOMException::NOT_FOUND_ERR, 0, GetDOMNamedNodeMapMemoryManager);
removed = fNodes->elementAt(i);
fNodes->removeElementAt(i);
castToNodeImpl(removed)->fOwnerNode = fOwnerNode->getOwnerDocument();
castToNodeImpl(removed)->isOwned(false);
// Replace it if it had a default value
// (DOM spec level 1 - Element Interface)
if (hasDefaults() && (removed != 0))
{
DOMAttrMapImpl* defAttrs = ((DOMElementImpl*)fOwnerNode)->getDefaultAttributes();
DOMAttr* attr = (DOMAttr*)(defAttrs->getNamedItem(name));
if (attr != 0)
{
DOMAttr* newAttr = (DOMAttr*)attr->cloneNode(true);
setNamedItem(newAttr);
}
}
return removed;
}
DOMNode *DOMAttrMapImpl::removeNamedItemNS(const XMLCh *namespaceURI, const XMLCh *localName)
{
if (this->readOnly())
throw DOMException(
DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNamedNodeMapMemoryManager);
int i = findNamePoint(namespaceURI, localName);
if (i < 0)
throw DOMException(DOMException::NOT_FOUND_ERR, 0, GetDOMNamedNodeMapMemoryManager);
DOMNode * removed = fNodes -> elementAt(i);
fNodes -> removeElementAt(i); //remove n from nodes
castToNodeImpl(removed)->fOwnerNode = fOwnerNode->getOwnerDocument();
castToNodeImpl(removed)->isOwned(false);
// Replace it if it had a default value
// (DOM spec level 2 - Element Interface)
if (hasDefaults() && (removed != 0))
{
DOMAttrMapImpl* defAttrs = ((DOMElementImpl*)fOwnerNode)->getDefaultAttributes();
DOMAttr* attr = (DOMAttr*)(defAttrs->getNamedItemNS(namespaceURI, localName));
if (attr != 0)
{
DOMAttr* newAttr = (DOMAttr*)attr->cloneNode(true);
setNamedItemNS(newAttr);
}
}
return removed;
}
// remove the name using index
// avoid calling findNamePoint again if the index is already known
DOMNode * DOMAttrMapImpl::removeNamedItemAt(XMLSize_t index)
{
if (this->readOnly())
throw DOMException(
DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNamedNodeMapMemoryManager);
DOMNode *removed = item(index);
if(!removed)
throw DOMException(DOMException::NOT_FOUND_ERR, 0, GetDOMNamedNodeMapMemoryManager);
fNodes->removeElementAt(index);
castToNodeImpl(removed)->fOwnerNode = fOwnerNode->getOwnerDocument();
castToNodeImpl(removed)->isOwned(false);
// Replace it if it had a default value
// (DOM spec level 1 - Element Interface)
if (hasDefaults() && (removed != 0))
{
DOMAttrMapImpl* defAttrs = ((DOMElementImpl*)fOwnerNode)->getDefaultAttributes();
const XMLCh* localName = removed->getLocalName();
DOMAttr* attr = 0;
if (localName)
attr = (DOMAttr*)(defAttrs->getNamedItemNS(removed->getNamespaceURI(), localName));
else
attr = (DOMAttr*)(defAttrs->getNamedItem(((DOMAttr*)removed)->getName()));
if (attr != 0)
{
DOMAttr* newAttr = (DOMAttr*)attr->cloneNode(true);
setNamedItem(newAttr);
}
}
return removed;
}
/**
* Get this AttributeMap in sync with the given "defaults" map.
* @param defaults The default attributes map to sync with.
*/
void DOMAttrMapImpl::reconcileDefaultAttributes(const DOMAttrMapImpl* defaults) {
// remove any existing default
XMLSize_t nsize = getLength();
for (XMLSSize_t i = nsize - 1; i >= 0; i--) {
DOMAttr* attr = (DOMAttr*)item(i);
if (!attr->getSpecified()) {
removeNamedItemAt(i);
}
}
hasDefaults(false);
// add the new defaults
if (defaults) {
hasDefaults(true);
if (nsize == 0) {
cloneContent(defaults);
}
else {
XMLSize_t dsize = defaults->getLength();
for (XMLSize_t n = 0; n < dsize; n++) {
DOMAttr* attr = (DOMAttr*)defaults->item(n);
DOMAttr* newAttr = (DOMAttr*)attr->cloneNode(true);
setNamedItemNS(newAttr);
DOMAttrImpl* newAttrImpl = (DOMAttrImpl*) newAttr;
newAttrImpl->setSpecified(false);
}
}
}
} // reconcileDefaults()
/**
* Move specified attributes from the given map to this one
*/
void DOMAttrMapImpl::moveSpecifiedAttributes(DOMAttrMapImpl* srcmap) {
XMLSize_t nsize = srcmap->getLength();
for (XMLSSize_t i = nsize - 1; i >= 0; i--) {
DOMAttr* attr = (DOMAttr*)srcmap->item(i);
if (attr->getSpecified()) {
srcmap->removeNamedItemAt(i);
}
if (attr->getLocalName())
setNamedItemNS(attr);
else
setNamedItem(attr);
}
} // moveSpecifiedAttributes(AttributeMap):void
XMLSize_t DOMAttrMapImpl::getLength() const
{
return (fNodes != 0) ? fNodes->size() : 0;
}
DOMNode * DOMAttrMapImpl::item(XMLSize_t index) const
{
return (fNodes != 0 && index < fNodes->size()) ?
fNodes->elementAt(index) : 0;
}
XERCES_CPP_NAMESPACE_END