Newer
Older
/*
* 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
Boris Kolpackov
committed
*
Boris Kolpackov
committed
*
* 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$
*/
#include "DOMDocumentImpl.hpp"
#include "DOMCasts.hpp"
#include "DOMConfigurationImpl.hpp"
#include "DOMDocumentTypeImpl.hpp"
#include "DOMAttrImpl.hpp"
#include "DOMAttrNSImpl.hpp"
#include "DOMCDATASectionImpl.hpp"
#include "DOMCommentImpl.hpp"
#include "DOMDeepNodeListImpl.hpp"
#include "DOMDocumentFragmentImpl.hpp"
#include "DOMElementImpl.hpp"
#include "XSDElementNSImpl.hpp"
#include "DOMEntityImpl.hpp"
#include "DOMEntityReferenceImpl.hpp"
#include "DOMNotationImpl.hpp"
#include "DOMProcessingInstructionImpl.hpp"
#include "DOMTextImpl.hpp"
#include "DOMTreeWalkerImpl.hpp"
#include "DOMNodeIteratorImpl.hpp"
#include "DOMNodeIDMap.hpp"
#include "DOMRangeImpl.hpp"
Alberto Massari
committed
#include "DOMTypeInfoImpl.hpp"
Alberto Massari
committed
#include "DOMXPathExpressionImpl.hpp"
#include "DOMXPathNSResolverImpl.hpp"
#include <xercesc/dom/DOMImplementation.hpp>
#include <xercesc/framework/MemoryManager.hpp>
Neil Graham
committed
#include <xercesc/util/OutOfMemoryException.hpp>
Boris Kolpackov
committed
#include <xercesc/util/XMLInitializer.hpp>
Boris Kolpackov
committed
#include <xercesc/util/Janitor.hpp>
Alberto Massari
committed
// The chunk size to allocate from the system allocator.
Boris Kolpackov
committed
static XMLSize_t kInitialHeapAllocSize = 0x4000;
static XMLSize_t kMaxHeapAllocSize = 0x80000;
static XMLSize_t kMaxSubAllocationSize = 0x0100; // Any request for more bytes
// than this will be handled by
// allocating directly with system.
void XMLInitializer::initializeDOMHeap (XMLSize_t initialHeapAllocSize,
XMLSize_t maxHeapAllocSize,
XMLSize_t maxSubAllocationSize)
{
kInitialHeapAllocSize = initialHeapAllocSize;
kMaxHeapAllocSize = maxHeapAllocSize;
kMaxSubAllocationSize = maxSubAllocationSize;
}
Alberto Massari
committed
//
// Constructors. Warning - be very careful with the ordering of initialization
// of the heap. Ordering depends on the order of declaration
// in the .hpp file, not on the order of initializers here
// in the constructor. The heap declaration can not be
// first - fNode and fParent must be first for the casting
// functions in DOMCasts to work correctly. This means that
// fNode and fParent constructors used here can not
// allocate.
//
Alberto Massari
committed
DOMDocumentImpl::DOMDocumentImpl(DOMImplementation* domImpl, MemoryManager* const manager)
: fNode(this),
fParent(this),
fNodeIDMap(0),
fInputEncoding(0),
fXmlEncoding(0),
fXmlStandalone(false),
fXmlVersion(0),
David Abram Cargill
committed
fDOMConfiguration(0),
fUserDataTableKeys(17, manager),
Boris Kolpackov
committed
fCurrentBlock(0),
David Abram Cargill
committed
fFreePtr(0),
fFreeBytesRemaining(0),
Alberto Massari
committed
fHeapAllocSize(kInitialHeapAllocSize),
fRecycleNodePtr(0),
David Abram Cargill
committed
fNodeListPool(0),
fDocType(0),
fDocElement(0),
Boris Kolpackov
committed
fNameTableSize(257),
Boris Kolpackov
committed
fNormalizer(0),
David Abram Cargill
committed
fRanges(0),
fNodeIterators(0),
fMemoryManager(manager),
Alberto Massari
committed
fDOMImplementation(domImpl),
Boris Kolpackov
committed
fChanges(0),
{
Boris Kolpackov
committed
fNameTable = (DOMStringPoolEntry**)allocate (
sizeof (DOMStringPoolEntry*) * fNameTableSize);
for (XMLSize_t i = 0; i < fNameTableSize; i++)
fNameTable[i] = 0;
David Abram Cargill
committed
}
//DOM Level 2
DOMDocumentImpl::DOMDocumentImpl(const XMLCh *fNamespaceURI,
const XMLCh *qualifiedName,
DOMDocumentType *doctype,
Boris Kolpackov
committed
DOMImplementation* domImpl,
MemoryManager* const manager)
: fNode(this),
fParent(this),
fNodeIDMap(0),
fInputEncoding(0),
fXmlEncoding(0),
fXmlStandalone(false),
fXmlVersion(0),
David Abram Cargill
committed
fDOMConfiguration(0),
fUserDataTableKeys(17, manager),
Boris Kolpackov
committed
fCurrentBlock(0),
David Abram Cargill
committed
fFreePtr(0),
fFreeBytesRemaining(0),
Alberto Massari
committed
fHeapAllocSize(kInitialHeapAllocSize),
fRecycleNodePtr(0),
fRecycleBufferPtr(0),
David Abram Cargill
committed
fNodeListPool(0),
fDocType(0),
fDocElement(0),
Boris Kolpackov
committed
fNameTableSize(257),
Boris Kolpackov
committed
fNormalizer(0),
David Abram Cargill
committed
fRanges(0),
fNodeIterators(0),
fMemoryManager(manager),
Alberto Massari
committed
fDOMImplementation(domImpl),
David Abram Cargill
committed
fChanges(0),
{
Boris Kolpackov
committed
fNameTable = (DOMStringPoolEntry**)allocate (
sizeof (DOMStringPoolEntry*) * fNameTableSize);
for (XMLSize_t i = 0; i < fNameTableSize; i++)
fNameTable[i] = 0;
try {
setDocumentType(doctype);
if (qualifiedName)
appendChild(createElementNS(fNamespaceURI, qualifiedName)); //root element
else if (fNamespaceURI)
throw DOMException(DOMException::NAMESPACE_ERR, 0, getMemoryManager());
}
Neil Graham
committed
catch(const OutOfMemoryException&)
{
throw;
}
catch (...) {
this->deleteHeap();
throw;
}
}
void DOMDocumentImpl::setDocumentType(DOMDocumentType *doctype)
{
// New doctypes can be created either with the factory methods on DOMImplementation, in
// which case ownerDocument will be 0, or with methods on DocumentImpl, in which case
// ownerDocument will be set, but the DocType won't yet be a child of the document.
Boris Kolpackov
committed
//
DOMDocument* doc = doctype->getOwnerDocument();
if (doc != 0 && doc != this)
throw DOMException( //one doctype can belong to only one DOMDocumentImpl
DOMException::WRONG_DOCUMENT_ERR, 0, getMemoryManager());
DOMDocumentTypeImpl* doctypeImpl = (DOMDocumentTypeImpl*) doctype;
doctypeImpl->setOwnerDocument(this);
// The doctype can not have any Entities or Notations yet, because they can not
// be created except through factory methods on a document.
// revisit. What if this doctype is already a child of the document?
}
DOMDocumentImpl::~DOMDocumentImpl()
{
Boris Kolpackov
committed
// While DOMConfiguration is allocated on the Document's heap, itself
// it uses the memory manager directly. This means that while we cannot
// delete with operator delete, we need to call its d-tor.
//
if (fDOMConfiguration)
fDOMConfiguration->~DOMConfiguration ();
// Clean up the fNodeListPool
if (fNodeListPool)
fNodeListPool->cleanup();
if (fRanges)
delete fRanges; //fRanges->cleanup();
if (fNodeIterators)
delete fNodeIterators;//fNodeIterators->cleanup();
delete fUserDataTable;//fUserDataTable->cleanup();
if (fRecycleNodePtr) {
fRecycleNodePtr->deleteAllElements();
delete fRecycleNodePtr;
}
if (fRecycleBufferPtr) {
delete fRecycleBufferPtr;
}
// Delete the heap for this document. This uncerimoniously yanks the storage
// out from under all of the nodes in the document. Destructors are NOT called.
this->deleteHeap();
David Abram Cargill
committed
}
DOMNode *DOMDocumentImpl::cloneNode(bool deep) const {
Alberto Massari
committed
// Note: the cloned document node goes on the same heap we live in.
Alberto Massari
committed
DOMDocumentImpl *newdoc = new (fMemoryManager) DOMDocumentImpl(fDOMImplementation, fMemoryManager);
if(fXmlEncoding && *fXmlEncoding)
newdoc->setXmlEncoding(fXmlEncoding);
if(fXmlVersion && *fXmlVersion)
newdoc->setXmlVersion(fXmlVersion);
newdoc->setXmlStandalone(fXmlStandalone);
// then the children by _importing_ them
if (deep)
for (DOMNode *n = this->getFirstChild(); n != 0; n = n->getNextSibling()) {
newdoc->appendChild(newdoc->importNode(n, true, true));
}
fNode.callUserDataHandlers(DOMUserDataHandler::NODE_CLONED, this, newdoc);
return newdoc;
David Abram Cargill
committed
}
const XMLCh * DOMDocumentImpl::getNodeName() const {
static const XMLCh nam[] = // "#document"
{chPound, chLatin_d, chLatin_o, chLatin_c, chLatin_u, chLatin_m, chLatin_e, chLatin_n, chLatin_t, 0};
return nam;
}
Boris Kolpackov
committed
DOMNode::NodeType DOMDocumentImpl::getNodeType() const {
return DOMNode::DOCUMENT_NODE;
David Abram Cargill
committed
}
// even though ownerDocument refers to this in this implementation
// the DOM Level 2 spec says it must be 0, so make it appear so
DOMDocument * DOMDocumentImpl::getOwnerDocument() const {
return 0;
}
DOMAttr *DOMDocumentImpl::createAttribute(const XMLCh *nam)
{
throw DOMException(DOMException::INVALID_CHARACTER_ERR,0, getMemoryManager());
Alberto Massari
committed
return new (this, DOMMemoryManager::ATTR_OBJECT) DOMAttrImpl(this,nam);
David Abram Cargill
committed
}
DOMCDATASection *DOMDocumentImpl::createCDATASection(const XMLCh *data) {
Alberto Massari
committed
return new (this, DOMMemoryManager::CDATA_SECTION_OBJECT) DOMCDATASectionImpl(this,data);
David Abram Cargill
committed
}
DOMComment *DOMDocumentImpl::createComment(const XMLCh *data)
{
Alberto Massari
committed
return new (this, DOMMemoryManager::COMMENT_OBJECT) DOMCommentImpl(this, data);
David Abram Cargill
committed
}
DOMDocumentFragment *DOMDocumentImpl::createDocumentFragment()
{
Alberto Massari
committed
return new (this, DOMMemoryManager::DOCUMENT_FRAGMENT_OBJECT) DOMDocumentFragmentImpl(this);
David Abram Cargill
committed
}
DOMDocumentType *DOMDocumentImpl::createDocumentType(const XMLCh *nam)
{
throw DOMException(
DOMException::INVALID_CHARACTER_ERR, 0, getMemoryManager());
Alberto Massari
committed
return new (this, DOMMemoryManager::DOCUMENT_TYPE_OBJECT) DOMDocumentTypeImpl(this, nam, false);
David Abram Cargill
committed
}
DOMDocumentType *
DOMDocumentImpl::createDocumentType(const XMLCh *qualifiedName,
const XMLCh *publicId,
const XMLCh *systemId)
{
throw DOMException(
DOMException::INVALID_CHARACTER_ERR, 0, getMemoryManager());
Alberto Massari
committed
return new (this, DOMMemoryManager::DOCUMENT_TYPE_OBJECT) DOMDocumentTypeImpl(this, qualifiedName, publicId, systemId, false);
David Abram Cargill
committed
}
DOMElement *DOMDocumentImpl::createElement(const XMLCh *tagName)
{
throw DOMException(DOMException::INVALID_CHARACTER_ERR,0, getMemoryManager());
Alberto Massari
committed
return new (this, DOMMemoryManager::ELEMENT_OBJECT) DOMElementImpl(this,tagName);
David Abram Cargill
committed
}
DOMElement *DOMDocumentImpl::createElementNoCheck(const XMLCh *tagName)
{
Alberto Massari
committed
return new (this, DOMMemoryManager::ELEMENT_OBJECT) DOMElementImpl(this, tagName);
David Abram Cargill
committed
}
DOMEntity *DOMDocumentImpl::createEntity(const XMLCh *nam)
{
throw DOMException(
DOMException::INVALID_CHARACTER_ERR, 0, getMemoryManager());
Alberto Massari
committed
return new (this, DOMMemoryManager::ENTITY_OBJECT) DOMEntityImpl(this, nam);
David Abram Cargill
committed
}
DOMEntityReference *DOMDocumentImpl::createEntityReference(const XMLCh *nam)
{
throw DOMException(
DOMException::INVALID_CHARACTER_ERR, 0, getMemoryManager());
Alberto Massari
committed
return new (this, DOMMemoryManager::ENTITY_REFERENCE_OBJECT) DOMEntityReferenceImpl(this, nam);
David Abram Cargill
committed
}
DOMEntityReference *DOMDocumentImpl::createEntityReferenceByParser(const XMLCh *nam)
{
if (!nam || !isXMLName(nam))
throw DOMException(
DOMException::INVALID_CHARACTER_ERR, 0, getMemoryManager());
Alberto Massari
committed
return new (this, DOMMemoryManager::ENTITY_REFERENCE_OBJECT) DOMEntityReferenceImpl(this, nam, false);
David Abram Cargill
committed
}
DOMNotation *DOMDocumentImpl::createNotation(const XMLCh *nam)
{
throw DOMException(
DOMException::INVALID_CHARACTER_ERR, 0, getMemoryManager());
Alberto Massari
committed
return new (this, DOMMemoryManager::NOTATION_OBJECT) DOMNotationImpl(this, nam);
David Abram Cargill
committed
}
DOMProcessingInstruction *DOMDocumentImpl::createProcessingInstruction(
const XMLCh *target, const XMLCh *data)
{
throw DOMException(DOMException::INVALID_CHARACTER_ERR,0, getMemoryManager());
Alberto Massari
committed
return new (this, DOMMemoryManager::PROCESSING_INSTRUCTION_OBJECT) DOMProcessingInstructionImpl(this,target,data);
David Abram Cargill
committed
}
DOMText *DOMDocumentImpl::createTextNode(const XMLCh *data)
{
Alberto Massari
committed
return new (this, DOMMemoryManager::TEXT_OBJECT) DOMTextImpl(this,data);
David Abram Cargill
committed
}
DOMNodeIterator* DOMDocumentImpl::createNodeIterator (
Boris Kolpackov
committed
DOMNode *root,
DOMNodeFilter::ShowType whatToShow,
DOMNodeFilter* filter,
bool entityReferenceExpansion)
{
if (!root) {
throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, getMemoryManager());
return 0;
}
DOMNodeIteratorImpl* nodeIterator = new (this) DOMNodeIteratorImpl(this, root, whatToShow, filter, entityReferenceExpansion);
if (fNodeIterators == 0L) {
//fNodeIterators = new (this) NodeIterators(1, false);
fNodeIterators = new (fMemoryManager) NodeIterators(1, false, fMemoryManager);
}
fNodeIterators->addElement(nodeIterator);
return nodeIterator;
}
NodeIterators* DOMDocumentImpl::getNodeIterators() const
{
return fNodeIterators;
}
void DOMDocumentImpl::removeNodeIterator(DOMNodeIteratorImpl* nodeIterator)
{
if (fNodeIterators != 0) {
XMLSize_t sz = fNodeIterators->size();
if (sz !=0) {
for (XMLSize_t i =0; i<sz; i++) {
if (fNodeIterators->elementAt(i) == nodeIterator) {
fNodeIterators->removeElementAt(i);
break;
}
}
}
}
}
Gareth Reakes
committed
Boris Kolpackov
committed
DOMXPathExpression* DOMDocumentImpl::createExpression(const XMLCh * expression, const DOMXPathNSResolver *resolver)
Gareth Reakes
committed
{
Alberto Massari
committed
return new (getMemoryManager()) DOMXPathExpressionImpl(expression, resolver, getMemoryManager());
Gareth Reakes
committed
}
DOMXPathNSResolver* DOMDocumentImpl::createNSResolver(const DOMNode *nodeResolver)
Gareth Reakes
committed
{
return new (getMemoryManager()) DOMXPathNSResolverImpl(nodeResolver, getMemoryManager());
Gareth Reakes
committed
}
Boris Kolpackov
committed
DOMXPathResult* DOMDocumentImpl::evaluate(const XMLCh *expression,
const DOMNode *contextNode,
const DOMXPathNSResolver *resolver,
Boris Kolpackov
committed
DOMXPathResult::ResultType type,
Boris Kolpackov
committed
DOMXPathResult* result)
Gareth Reakes
committed
{
Boris Kolpackov
committed
JanitorMemFunCall<DOMXPathExpression> expr(
createExpression(expression, resolver),
&DOMXPathExpression::release);
return expr->evaluate(contextNode, type, result);
Gareth Reakes
committed
}
Boris Kolpackov
committed
DOMTreeWalker* DOMDocumentImpl::createTreeWalker (
DOMNode *root,
DOMNodeFilter::ShowType whatToShow,
DOMNodeFilter* filter,
bool entityReferenceExpansion)
{
if (!root) {
throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, getMemoryManager());
return 0;
}
return new (this) DOMTreeWalkerImpl(root, whatToShow, filter, entityReferenceExpansion);
}
DOMDocumentType *DOMDocumentImpl::getDoctype() const
{
return fDocType;
David Abram Cargill
committed
}
DOMElement *DOMDocumentImpl::getDocumentElement() const
{
return fDocElement;
David Abram Cargill
committed
}
DOMNodeList *DOMDocumentImpl::getElementsByTagName(const XMLCh *tagname) const
{
// cast off the const of this because we will update the fNodeListPool
return ((DOMDocumentImpl*)this)->getDeepNodeList(this,tagname);
David Abram Cargill
committed
}
DOMImplementation *DOMDocumentImpl::getImplementation() const {
Alberto Massari
committed
return fDOMImplementation;
}
DOMNode *DOMDocumentImpl::insertBefore(DOMNode *newChild, DOMNode *refChild)
{
// Only one such child permitted
if(
(newChild->getNodeType() == DOMNode::ELEMENT_NODE && fDocElement!=0)
||
(newChild->getNodeType() == DOMNode::DOCUMENT_TYPE_NODE && fDocType!=0)
)
throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0, getMemoryManager());
// if the newChild is a documenttype node created from domimplementation, set the ownerDoc first
if ((newChild->getNodeType() == DOMNode::DOCUMENT_TYPE_NODE) && !newChild->getOwnerDocument())
fParent.insertBefore(newChild,refChild);
// If insert succeeded, cache the kid appropriately
if(newChild->getNodeType() == DOMNode::ELEMENT_NODE)
fDocElement=(DOMElement *)newChild;
else if(newChild->getNodeType() == DOMNode::DOCUMENT_TYPE_NODE)
fDocType=(DOMDocumentType *)newChild;
return newChild;
David Abram Cargill
committed
}
DOMNode* DOMDocumentImpl::replaceChild(DOMNode *newChild, DOMNode *oldChild) {
DOMDocumentType* tempDocType = fDocType;
DOMElement* tempDocElement = fDocElement;
if(oldChild->getNodeType() == DOMNode::DOCUMENT_TYPE_NODE)
fDocType=0;
else if(oldChild->getNodeType() == DOMNode::ELEMENT_NODE)
fDocElement=0;
try {
insertBefore(newChild, oldChild);
// changed() already done.
if((oldChild->getNodeType() == DOMNode::DOCUMENT_TYPE_NODE)
|| (oldChild->getNodeType() == DOMNode::ELEMENT_NODE))
return fParent.removeChild(oldChild);
else
return removeChild(oldChild);
}
Neil Graham
committed
catch(const OutOfMemoryException&)
{
throw;
}
catch(...) {
fDocType = tempDocType;
fDocElement = tempDocElement;
throw;
}
bool DOMDocumentImpl::isXMLName(const XMLCh *s)
{
// fXmlVersion points directly to the static constants
if (fXmlVersion==XMLUni::fgVersion1_1)
return XMLChar1_1::isValidName(s);
return XMLChar1_0::isValidName(s);
David Abram Cargill
committed
}
DOMNode *DOMDocumentImpl::removeChild(DOMNode *oldChild)
{
fParent.removeChild(oldChild);
// If remove succeeded, un-cache the kid appropriately
if(oldChild->getNodeType() == DOMNode::ELEMENT_NODE)
fDocElement=0;
else if(oldChild->getNodeType() == DOMNode::DOCUMENT_TYPE_NODE)
fDocType=0;
return oldChild;
David Abram Cargill
committed
}
void DOMDocumentImpl::setNodeValue(const XMLCh *x)
{
fNode.setNodeValue(x);
David Abram Cargill
committed
}
//Introduced in DOM Level 2
DOMNode *DOMDocumentImpl::importNode(const DOMNode *source, bool deep)
{
}
DOMElement *DOMDocumentImpl::createElementNS(const XMLCh *fNamespaceURI,
{
throw DOMException(DOMException::INVALID_CHARACTER_ERR,0, getMemoryManager());
Alberto Massari
committed
return new (this, DOMMemoryManager::ELEMENT_NS_OBJECT) DOMElementNSImpl(this, fNamespaceURI, qualifiedName);
}
DOMElement *DOMDocumentImpl::createElementNS(const XMLCh *fNamespaceURI,
const XMLCh *qualifiedName,
Boris Kolpackov
committed
const XMLFileLoc lineNo,
const XMLFileLoc columnNo)
{
throw DOMException(DOMException::INVALID_CHARACTER_ERR,0, getMemoryManager());
return new (this) XSDElementNSImpl(this, fNamespaceURI, qualifiedName, lineNo, columnNo);
}
DOMAttr *DOMDocumentImpl::createAttributeNS(const XMLCh *fNamespaceURI,
{
throw DOMException(DOMException::INVALID_CHARACTER_ERR,0, getMemoryManager());
Alberto Massari
committed
return new (this, DOMMemoryManager::ATTR_NS_OBJECT) DOMAttrNSImpl(this, fNamespaceURI, qualifiedName);
}
DOMNodeList *DOMDocumentImpl::getElementsByTagNameNS(const XMLCh *fNamespaceURI,
{
// cast off the const of this because we will update the fNodeListPool
return ((DOMDocumentImpl*)this)->getDeepNodeList(this, fNamespaceURI, fLocalName);
}
DOMElement *DOMDocumentImpl::getElementById(const XMLCh *elementId) const
{
if (fNodeIDMap == 0)
return 0;
DOMAttr *theAttr = fNodeIDMap->find(elementId);
if (theAttr == 0)
return theAttr->getOwnerElement();
}
const XMLCh* DOMDocumentImpl::getBaseURI() const
David Abram Cargill
committed
}
DOMRange* DOMDocumentImpl::createRange()
{
DOMRangeImpl* range = new (this) DOMRangeImpl(this, fMemoryManager);
if (fRanges == 0L) {
//fRanges = new (this) Ranges(1, false);
fRanges = new (fMemoryManager) Ranges(1, false, fMemoryManager); // XMemory
}
fRanges->addElement(range);
return range;
}
Ranges* DOMDocumentImpl::getRanges() const
{
return fRanges;
}
void DOMDocumentImpl::removeRange(DOMRangeImpl* range)
{
if (fRanges != 0) {
XMLSize_t sz = fRanges->size();
if (sz !=0) {
for (XMLSize_t i =0; i<sz; i++) {
if (fRanges->elementAt(i) == range) {
fRanges->removeElementAt(i);
break;
}
}
}
}
}
/** Uses the kidOK lookup table to check whether the proposed
tree structure is legal.
????? It feels like there must be a more efficient solution,
but for the life of me I can't think what it would be.
*/
bool DOMDocumentImpl::isKidOK(DOMNode *parent, DOMNode *child)
{
static int kidOK[14];
if (kidOK[DOMNode::ATTRIBUTE_NODE] == 0)
{
kidOK[DOMNode::DOCUMENT_NODE] =
1 << DOMNode::ELEMENT_NODE |
1 << DOMNode::PROCESSING_INSTRUCTION_NODE |
1 << DOMNode::COMMENT_NODE |
kidOK[DOMNode::DOCUMENT_FRAGMENT_NODE] =
kidOK[DOMNode::ENTITY_NODE] =
kidOK[DOMNode::ENTITY_REFERENCE_NODE] =
kidOK[DOMNode::ELEMENT_NODE] =
1 << DOMNode::ELEMENT_NODE |
1 << DOMNode::PROCESSING_INSTRUCTION_NODE |
1 << DOMNode::COMMENT_NODE |
1 << DOMNode::TEXT_NODE |
1 << DOMNode::CDATA_SECTION_NODE |
kidOK[DOMNode::ATTRIBUTE_NODE] =
1 << DOMNode::TEXT_NODE |
1 << DOMNode::ENTITY_REFERENCE_NODE;
kidOK[DOMNode::PROCESSING_INSTRUCTION_NODE] =
kidOK[DOMNode::COMMENT_NODE] =
kidOK[DOMNode::TEXT_NODE] =
kidOK[DOMNode::CDATA_SECTION_NODE] =
kidOK[DOMNode::NOTATION_NODE] =
0;
David Abram Cargill
committed
}
int p=parent->getNodeType();
int ch = child->getNodeType();
Boris Kolpackov
committed
return ((kidOK[p] & 1<<ch) != 0) ||
(p==DOMNode::DOCUMENT_NODE && ch==DOMNode::TEXT_NODE &&
((XMLString::equals(((DOMDocument*)parent)->getXmlVersion(), XMLUni::fgVersion1_1))?
XMLChar1_1::isAllSpaces(child->getNodeValue(), XMLString::stringLen(child->getNodeValue())):
XMLChar1_0::isAllSpaces(child->getNodeValue(), XMLString::stringLen(child->getNodeValue())))
);
}
void DOMDocumentImpl::changed()
{
fChanges++;
}
int DOMDocumentImpl::changes() const{
return fChanges;
David Abram Cargill
committed
}
//
// Delegation for functions inherited from DOMNode
//
David Abram Cargill
committed
DOMNode* DOMDocumentImpl::appendChild(DOMNode *newChild) {return insertBefore(newChild, 0); }
DOMNamedNodeMap* DOMDocumentImpl::getAttributes() const {return fNode.getAttributes (); }
DOMNodeList* DOMDocumentImpl::getChildNodes() const {return fParent.getChildNodes (); }
DOMNode* DOMDocumentImpl::getFirstChild() const {return fParent.getFirstChild (); }
DOMNode* DOMDocumentImpl::getLastChild() const {return fParent.getLastChild (); }
const XMLCh* DOMDocumentImpl::getLocalName() const {return fNode.getLocalName (); }
const XMLCh* DOMDocumentImpl::getNamespaceURI() const {return fNode.getNamespaceURI (); }
DOMNode* DOMDocumentImpl::getNextSibling() const {return fNode.getNextSibling (); }
const XMLCh* DOMDocumentImpl::getNodeValue() const {return fNode.getNodeValue (); }
const XMLCh* DOMDocumentImpl::getPrefix() const {return fNode.getPrefix (); }
DOMNode* DOMDocumentImpl::getParentNode() const {return fNode.getParentNode (); }
DOMNode* DOMDocumentImpl::getPreviousSibling() const {return fNode.getPreviousSibling (); }
bool DOMDocumentImpl::hasChildNodes() const {return fParent.hasChildNodes (); }
void DOMDocumentImpl::normalize() {fParent.normalize (); }
void DOMDocumentImpl::setPrefix(const XMLCh *prefix) {fNode.setPrefix(prefix); }
bool DOMDocumentImpl::hasAttributes() const {return fNode.hasAttributes(); }
bool DOMDocumentImpl::isSameNode(const DOMNode* other) const {return fNode.isSameNode(other);}
bool DOMDocumentImpl::isEqualNode(const DOMNode* arg) const {return fParent.isEqualNode(arg);}
void* DOMDocumentImpl::setUserData(const XMLCh* key, void* data, DOMUserDataHandler* handler)
David Abram Cargill
committed
{return fNode.setUserData(key, data, handler); }
void* DOMDocumentImpl::getUserData(const XMLCh* key) const {return fNode.getUserData(key); }
short DOMDocumentImpl::compareDocumentPosition(const DOMNode* other) const {return fNode.compareDocumentPosition(other); }
David Abram Cargill
committed
const XMLCh* DOMDocumentImpl::getTextContent() const {return fNode.getTextContent(); }
void DOMDocumentImpl::setTextContent(const XMLCh* textContent){fNode.setTextContent(textContent); }
const XMLCh* DOMDocumentImpl::lookupPrefix(const XMLCh* namespaceURI) const {return fNode.lookupPrefix(namespaceURI); }
David Abram Cargill
committed
bool DOMDocumentImpl::isDefaultNamespace(const XMLCh* namespaceURI) const {return fNode.isDefaultNamespace(namespaceURI); }
const XMLCh* DOMDocumentImpl::lookupNamespaceURI(const XMLCh* prefix) const {return fNode.lookupNamespaceURI(prefix); }
//-----------------------------------------------------------------------
//
// Per Document Heap and Heap Helper functions
//
// revisit - this stuff should be a class of its own, rather than
// just lying around naked in DocumentImpl.
//
//-----------------------------------------------------------------------
XMLCh * DOMDocumentImpl::cloneString(const XMLCh *src)
{
if (!src) return 0;
Boris Kolpackov
committed
XMLSize_t len = XMLString::stringLen(src);
len = (len + 1) * sizeof(XMLCh);
len = (len % 4) + len;
XMLCh *newStr = (XMLCh *)this->allocate(len);
XMLString::copyString(newStr, src);
return newStr;
}
Alberto Massari
committed
XMLSize_t DOMDocumentImpl::getMemoryAllocationBlockSize() const
{
return fHeapAllocSize;
}
Alberto Massari
committed
void DOMDocumentImpl::setMemoryAllocationBlockSize(XMLSize_t size)
{
// the new size must be bigger than the maximum amount of each allocation
if(size>kMaxSubAllocationSize)
fHeapAllocSize=size;
}
void* DOMDocumentImpl::allocate(XMLSize_t amount)
Boris Kolpackov
committed
{
// Align the request size so that suballocated blocks
// beyond this one will be maintained at the same alignment.
amount = XMLPlatformUtils::alignPointerForNewBlockAllocation(amount);
// If the request is for a largish block, hand it off to the system
// allocator. The block still must be linked into the list of
// allocated blocks so that it will be deleted when the time comes.
if (amount > kMaxSubAllocationSize)
{
// The size of the header we add to our raw blocks
XMLSize_t sizeOfHeader = XMLPlatformUtils::alignPointerForNewBlockAllocation(sizeof(void *));
Boris Kolpackov
committed
// Try to allocate the block
void* newBlock;
newBlock = fMemoryManager->allocate(sizeOfHeader + amount);
// Link it into the list beyond current block, as current block
// is still being subdivided. If there is no current block
// then track that we have no bytes to further divide.
if (fCurrentBlock)
{
*(void **)newBlock = *(void **)fCurrentBlock;
*(void **)fCurrentBlock = newBlock;
}
else
{
*(void **)newBlock = 0;
fCurrentBlock = newBlock;
fFreePtr = 0;
fFreeBytesRemaining = 0;
}
void *retPtr = (char*)newBlock + sizeOfHeader;
return retPtr;
}
James David Berry
committed
// It's a normal (sub-allocatable) request.
// Are we out of room in our current block?
if (amount > fFreeBytesRemaining)
{
// Request doesn't fit in the current block.
// The size of the header we add to our raw blocks
XMLSize_t sizeOfHeader = XMLPlatformUtils::alignPointerForNewBlockAllocation(sizeof(void *));
James David Berry
committed
// Get a new block from the system allocator.
void* newBlock;
newBlock = fMemoryManager->allocate(fHeapAllocSize);
Boris Kolpackov
committed
*(void **)newBlock = fCurrentBlock;
fCurrentBlock = newBlock;
fFreePtr = (char *)newBlock + sizeOfHeader;
fFreeBytesRemaining = fHeapAllocSize - sizeOfHeader;
Alberto Massari
committed
if(fHeapAllocSize<kMaxHeapAllocSize)
fHeapAllocSize*=2;
}
// Subdivide the request off current block
void *retPtr = fFreePtr;
fFreePtr += amount;
fFreeBytesRemaining -= amount;
Boris Kolpackov
committed
}
void DOMDocumentImpl::deleteHeap()
{
while (fCurrentBlock != 0)
{
void *nextBlock = *(void **)fCurrentBlock;
fMemoryManager->deallocate(fCurrentBlock);
fCurrentBlock = nextBlock;
}
}
James David Berry
committed
DOMNodeList *DOMDocumentImpl::getDeepNodeList(const DOMNode *rootNode, const XMLCh *tagName)
{
if(!fNodeListPool) {
fNodeListPool = new (this) DOMDeepNodeListPool<DOMDeepNodeListImpl>(109, false);
}
DOMDeepNodeListImpl* retList = fNodeListPool->getByKey(rootNode, tagName, 0);
if (!retList) {
Alberto Massari
committed
XMLSize_t id = fNodeListPool->put((void*) rootNode, (XMLCh*) tagName, 0, new (this) DOMDeepNodeListImpl(rootNode, tagName));
retList = fNodeListPool->getById(id);
}
return retList;
}
DOMNodeList *DOMDocumentImpl::getDeepNodeList(const DOMNode *rootNode, //DOM Level 2
const XMLCh *namespaceURI,
const XMLCh *localName)
{
if(!fNodeListPool) {
fNodeListPool = new (this) DOMDeepNodeListPool<DOMDeepNodeListImpl>(109, false);
}
DOMDeepNodeListImpl* retList = fNodeListPool->getByKey(rootNode, localName, namespaceURI);
if (!retList) {
// the pool will adopt the DOMDeepNodeListImpl
Alberto Massari
committed
XMLSize_t id = fNodeListPool->put((void*) rootNode, (XMLCh*) localName, (XMLCh*) namespaceURI, new (this) DOMDeepNodeListImpl(rootNode, namespaceURI, localName));
retList = fNodeListPool->getById(id);
}
return retList;
}
const XMLCh* DOMDocumentImpl::getInputEncoding() const {
return fInputEncoding;
void DOMDocumentImpl::setInputEncoding(const XMLCh* actualEncoding){
fInputEncoding = cloneString(actualEncoding);
const XMLCh* DOMDocumentImpl::getXmlEncoding() const {
return fXmlEncoding;
void DOMDocumentImpl::setXmlEncoding(const XMLCh* encoding){
fXmlEncoding = cloneString(encoding);
bool DOMDocumentImpl::getXmlStandalone() const{
return fXmlStandalone;
void DOMDocumentImpl::setXmlStandalone(bool standalone){
fXmlStandalone = standalone;
const XMLCh* DOMDocumentImpl::getXmlVersion() const {
return fXmlVersion;
void DOMDocumentImpl::setXmlVersion(const XMLCh* version){
// store the static strings, so that comparisons will be faster
if(version==0)
fXmlVersion = 0;
else if(*version==0)
fXmlVersion = XMLUni::fgZeroLenString;
else if(XMLString::equals(version, XMLUni::fgVersion1_0))
fXmlVersion = XMLUni::fgVersion1_0;
else if(XMLString::equals(version, XMLUni::fgVersion1_1))
fXmlVersion = XMLUni::fgVersion1_1;
Boris Kolpackov
committed
else
throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, getMemoryManager());
const XMLCh* DOMDocumentImpl::getDocumentURI() const
{
return fDocumentURI;
}
void DOMDocumentImpl::setDocumentURI(const XMLCh* documentURI){