diff --git a/include/DOM/Attr.hpp b/include/DOM/Attr.hpp index 6efa777b..6f5ec974 100644 --- a/include/DOM/Attr.hpp +++ b/include/DOM/Attr.hpp @@ -31,6 +31,8 @@ class Attr : public Node Attr(const Attr& rhs) : NodeT(rhs) { } explicit Attr(const NodeT& rhs) : NodeT(rhs) { + if(NodeT::impl_ == 0) // null nodes can always be cast + return; if(rhs.getNodeType() != NodeT::ATTRIBUTE_NODE) throw std::bad_cast(); } // Attr diff --git a/include/DOM/CDATASection.hpp b/include/DOM/CDATASection.hpp index 9aa48f2d..ffb65b0d 100644 --- a/include/DOM/CDATASection.hpp +++ b/include/DOM/CDATASection.hpp @@ -25,6 +25,8 @@ class CDATASection : public Text CDATASection(const CDATASection& rhs) : Text(rhs) { } explicit CDATASection(const Node& rhs) : Text(rhs, 0) { + if(NodeT::impl_ == 0) // null nodes can always be cast + return; if(rhs.getNodeType() != Node_base::CDATA_SECTION_NODE) //throw std::runtime_error("bad_cast: Cannot convert Node to CDATA section"); throw std::bad_cast(); diff --git a/include/DOM/CharacterData.hpp b/include/DOM/CharacterData.hpp index 2b54dd98..f0d62a89 100644 --- a/include/DOM/CharacterData.hpp +++ b/include/DOM/CharacterData.hpp @@ -27,6 +27,8 @@ class CharacterData : public Node CharacterData(const CharacterData& rhs) : NodeT(rhs) { } explicit CharacterData(const NodeT& rhs) : NodeT(rhs) { + if(NodeT::impl_ == 0) // null nodes can always be cast + return; typename NodeT::Type type = rhs.getNodeType(); if((type != NodeT::TEXT_NODE) && (type != NodeT::CDATA_SECTION_NODE)) throw std::runtime_error("bad_cast: Cannot cast Node to Character Data"); diff --git a/include/DOM/Comment.hpp b/include/DOM/Comment.hpp index a7ce119c..0b3d6aee 100644 --- a/include/DOM/Comment.hpp +++ b/include/DOM/Comment.hpp @@ -24,7 +24,9 @@ class Comment : public CharacterData Comment(const Comment& rhs) : CharacterData(rhs) { } explicit Comment(const Node& rhs) : CharacterData(rhs) { - if(dynamic_cast*>(rhs.impl()) == 0) + if(NodeT::impl_ == 0) // null nodes can always be cast + return; + if(rhs.getNodeType() != Node::COMMENT_NODE) throw std::bad_cast(); } // Comment }; // class Comment diff --git a/include/DOM/Document.hpp b/include/DOM/Document.hpp index 538a0e7a..85d84a42 100644 --- a/include/DOM/Document.hpp +++ b/include/DOM/Document.hpp @@ -45,6 +45,8 @@ class Document : public Node Document(const Document& rhs) : Node(rhs) { } explicit Document(const Node& rhs) : Node(rhs) { + if(NodeT::impl_ == 0) // null nodes can always be cast + return; if(rhs.getNodeType() != Node::DOCUMENT_NODE) throw std::bad_cast(); } // Document diff --git a/include/DOM/DocumentFragment.hpp b/include/DOM/DocumentFragment.hpp index 8e4edfff..d9ec5545 100644 --- a/include/DOM/DocumentFragment.hpp +++ b/include/DOM/DocumentFragment.hpp @@ -26,6 +26,8 @@ class DocumentFragment : public Node DocumentFragment(const DocumentFragment& rhs) : Node(rhs) { } explicit DocumentFragment(const Node& rhs) : Node(rhs) { + if(NodeT::impl_ == 0) // null nodes can always be cast + return; if(rhs.getNodeType() != Node::DOCUMENT_FRAGMENT_NODE) throw std::bad_cast(); } diff --git a/include/DOM/DocumentType.hpp b/include/DOM/DocumentType.hpp index b9aa208f..7a39ee1e 100644 --- a/include/DOM/DocumentType.hpp +++ b/include/DOM/DocumentType.hpp @@ -33,6 +33,8 @@ class DocumentType : public Node DocumentType(const DocumentType& rhs) : NodeT(rhs) { } explicit DocumentType(const NodeT& rhs) : NodeT(rhs) { + if(NodeT::impl_ == 0) // null nodes can always be cast + return; if(rhs.getNodeType() != NodeT::DOCUMENT_TYPE_NODE) throw std::bad_cast(); } // DocumentType diff --git a/include/DOM/Element.hpp b/include/DOM/Element.hpp index 4083ae41..91c08f0d 100644 --- a/include/DOM/Element.hpp +++ b/include/DOM/Element.hpp @@ -34,6 +34,8 @@ class Element : public Node Element(const Element& rhs) : NodeT(rhs) { } explicit Element(const NodeT& rhs) : NodeT(rhs) { + if(NodeT::impl_ == 0) // null nodes can always be cast + return; if(rhs.getNodeType() != NodeT::ELEMENT_NODE) throw std::bad_cast(); } // Element diff --git a/include/DOM/Entity.hpp b/include/DOM/Entity.hpp index 120f7c9c..a176ae0a 100644 --- a/include/DOM/Entity.hpp +++ b/include/DOM/Entity.hpp @@ -24,22 +24,24 @@ class Entity : public Node typedef Entity_impl Entity_implT; Entity() : Node() { } - explicit Entity(Entity_impl* impl) : Node(impl) { } + explicit Entity(Entity_impl* impl) : Node(impl) { } Entity(const Entity& rhs) : Node(rhs) { } - explicit Entity(const Node& rhs) : Node(rhs) + explicit Entity(const Node& rhs) : Node(rhs) { - if(rhs.getNodeType() != Node::Entity_NODE) + if(NodeT::impl_ == 0) // null nodes can always be cast + return; + if(rhs.getNodeType() != Node_base::ENTITY_NODE) throw std::bad_cast(); } - stringT getPublicId() const { nImpl()->getPublicId(); } + stringT getPublicId() const { return nImpl()->getPublicId(); } - stringT getSystemId() const { nImpl()->getSystemId(); } + stringT getSystemId() const { return nImpl()->getSystemId(); } - stringT getNotationName() const { nImpl()->getNotationName(); } + stringT getNotationName() const { return nImpl()->getNotationName(); } private: - Entity_implT* nImpl() { return dynamic_cast(NodeT::impl()); } + Entity_implT* nImpl() const { return dynamic_cast(*NodeT::impl_); } }; // class Entity ////////////////////////////////////////////////////////// diff --git a/include/DOM/EntityReference.hpp b/include/DOM/EntityReference.hpp index 7f8c5eca..3206ef46 100644 --- a/include/DOM/EntityReference.hpp +++ b/include/DOM/EntityReference.hpp @@ -28,7 +28,9 @@ class EntityReference : public Node EntityReference(const EntityReference& rhs) : NodeT(rhs) { } explicit EntityReference(const NodeT& rhs) : NodeT(rhs) { - if(dynamic_cast(rhs.impl()) == 0) + if(NodeT::impl_ == 0) // null nodes can always be cast + return; + if(rhs.getNodeType() != Node_base::ENTITY_REFERENCE_NODE) throw std::bad_cast(); } // EntityReference }; // class EntityReference diff --git a/include/DOM/NodeList.hpp b/include/DOM/NodeList.hpp index ed93f04a..63d078ad 100644 --- a/include/DOM/NodeList.hpp +++ b/include/DOM/NodeList.hpp @@ -39,7 +39,12 @@ class NodeList Node item(unsigned int index) const { return impl_->item(index); } - unsigned int getLength() const { return impl_->getLength(); } + unsigned int getLength() const + { + if(impl_ == 0) + return 0; + return impl_->getLength(); + } // getLength private: Proxy > impl_; diff --git a/include/DOM/Notation.hpp b/include/DOM/Notation.hpp index 06d6207b..0d4d61dd 100644 --- a/include/DOM/Notation.hpp +++ b/include/DOM/Notation.hpp @@ -29,16 +29,18 @@ class Notation : public Node Notation(const Notation& rhs) : NodeT(rhs) { } explicit Notation(const NodeT& rhs) : NodeT(rhs) { + if(NodeT::impl_ == 0) // null nodes can always be cast + return; if(rhs.getNodeType() != Node_base::NOTATION_NODE) throw std::bad_cast(); } - stringT getPublicId() const { nImpl()->getPublicId(); } + stringT getPublicId() const { return nImpl()->getPublicId(); } - stringT getSystemId() const { nImpl()->getSystemId(); } + stringT getSystemId() const { return nImpl()->getSystemId(); } private: - Notation_implT* nImpl() { return dynamic_cast(NodeT::impl()); } + Notation_implT* nImpl() const { return dynamic_cast(*NodeT::impl_); } }; // class Notation ////////////////////////////////////////////////////////// diff --git a/include/DOM/ProcessingInstruction.hpp b/include/DOM/ProcessingInstruction.hpp index e9f86989..e598d219 100644 --- a/include/DOM/ProcessingInstruction.hpp +++ b/include/DOM/ProcessingInstruction.hpp @@ -26,6 +26,8 @@ class ProcessingInstruction : public Node ProcessingInstruction(const ProcessingInstruction& rhs) : Node(rhs) { } explicit ProcessingInstruction(const Node& rhs) : Node(rhs) { + if(NodeT::impl_ == 0) // null nodes can always be cast + return; if(rhs.getNodeType() != Node::PROCESSING_INSTRUCTION_NODE) throw std::bad_cast(); } diff --git a/include/DOM/Simple/AttrImpl.hpp b/include/DOM/Simple/AttrImpl.hpp index 6aeb280c..e5c5dc47 100644 --- a/include/DOM/Simple/AttrImpl.hpp +++ b/include/DOM/Simple/AttrImpl.hpp @@ -134,6 +134,14 @@ class AttrImpl : public DOM::Attr_impl, void setSpecified(bool specified) { specified_ = specified; } + bool isOrphaned() + { + if(!ownerElement_) + return true; + + return NodeT::ownerDoc_->isOrphaned(this); + } // isOrphaned + protected: void cloneChildren(AttrImpl* clone) const { diff --git a/include/DOM/Simple/AttrMap.hpp b/include/DOM/Simple/AttrMap.hpp index 4fab48f0..e3eea0ab 100644 --- a/include/DOM/Simple/AttrMap.hpp +++ b/include/DOM/Simple/AttrMap.hpp @@ -61,9 +61,15 @@ class AttrMap : public NamedNodeMapImpl DOMAttr_implT* setAttributeNode(DOMAttr_implT* newAttr) { + return dynamic_cast(setNamedItem(newAttr)); + } // setAttributeNode + virtual DOMNode_implT* setNamedItem(DOMNode_implT* newAttr) + { + throwIfReadOnly(); + checkNotInUse(newAttr); dynamic_cast(newAttr)->setOwnerElement(ownerElement_); return dynamic_cast(NamedNodeMapImplT::setNamedItem(newAttr)); - } // setAttributeNode + } // setNamedItem DOMAttr_implT* removeAttributeNode(DOMAttr_implT* oldAttr) { @@ -103,9 +109,15 @@ class AttrMap : public NamedNodeMapImpl DOMAttr_implT* setAttributeNodeNS(DOMAttr_implT* newAttr) { + return dynamic_cast(setNamedItemNS(newAttr)); + } // setAttributeNodeNS + virtual DOMNode_implT* setNamedItemNS(DOMNode_implT* newAttr) + { + throwIfReadOnly(); + checkNotInUse(newAttr); dynamic_cast(newAttr)->setOwnerElement(ownerElement_); return dynamic_cast(NamedNodeMapImplT::setNamedItemNS(newAttr)); - } // setAttributeNodeNS + } // setNamedItem bool hasAttribute(const stringT& name) const { @@ -181,6 +193,13 @@ class AttrMap : public NamedNodeMapImpl return 0; } // getDefaultAttrs + void checkNotInUse(DOMNode_implT* newAttr) + { + AttrImplT* attr = dynamic_cast(newAttr); + if(!attr->isOrphaned()) + throw DOM::DOMException(DOM::DOMException::INUSE_ATTRIBUTE_ERR); + } // checkNotInUse + ElementImplT* ownerElement_; }; // class AttrMap diff --git a/include/DOM/Simple/DocumentImpl.hpp b/include/DOM/Simple/DocumentImpl.hpp index 4c588378..8ef5c26d 100644 --- a/include/DOM/Simple/DocumentImpl.hpp +++ b/include/DOM/Simple/DocumentImpl.hpp @@ -437,6 +437,11 @@ class DocumentImpl : public DOM::Document_impl, orphans_.insert(node); } // orphaned + bool isOrphaned(NodeImplT* node) const + { + return orphans_.find(node) != orphans_.end(); + } // isOrphaned + void purge(NodeImplT* node) { orphans_.erase(node); diff --git a/include/DOM/Simple/ElementByTagImpl.hpp b/include/DOM/Simple/ElementByTagImpl.hpp index d01827c4..26076195 100644 --- a/include/DOM/Simple/ElementByTagImpl.hpp +++ b/include/DOM/Simple/ElementByTagImpl.hpp @@ -94,10 +94,10 @@ class ElementByTagList : public DOM::NodeList_impl private: void populate() const { - NodeListT dummy; + NodeListT dummy; nodes_.swap(dummy); - checkNode(rootNode_); + checkChildren(rootNode_); changes_ = ownerDoc_->changes(); } // populate @@ -116,11 +116,15 @@ class ElementByTagList : public DOM::NodeList_impl if((tagName_ == node->getNodeName()) || (allNames_ && node->getNodeType() == DOM::Node::ELEMENT_NODE)) nodes_.push_back(node); + checkChildren(node); + } // checkNode + + void checkChildren(DOM::Node_impl* node) const + { for(DOM::Node_impl* child = node->getFirstChild(); child != 0; child = child->getNextSibling()) if(child->getNodeType() == DOM::Node::ELEMENT_NODE) checkNode(child); - } // checkNode - + } // checkChildren typedef std::deque*> NodeListT; mutable NodeListT nodes_; diff --git a/include/DOM/Simple/NamedNodeMapImpl.hpp b/include/DOM/Simple/NamedNodeMapImpl.hpp index 9cc02422..0dc1dad9 100644 --- a/include/DOM/Simple/NamedNodeMapImpl.hpp +++ b/include/DOM/Simple/NamedNodeMapImpl.hpp @@ -160,13 +160,14 @@ class NamedNodeMapImpl : public DOM::NamedNodeMap_impl return nodes_[index]; } // item - private: + protected: void throwIfReadOnly() const { if(readOnly_) throw DOM::DOMException(DOM::DOMException::NO_MODIFICATION_ALLOWED_ERR); } // throwIfReadOnly + private: typedef std::deque NodeListT; NodeImplT* getNode(typename NodeListT::const_iterator n) const diff --git a/include/DOM/Simple/NodeImpl.hpp b/include/DOM/Simple/NodeImpl.hpp index 50b84224..aa43f1a9 100644 --- a/include/DOM/Simple/NodeImpl.hpp +++ b/include/DOM/Simple/NodeImpl.hpp @@ -416,8 +416,8 @@ class NodeImplWithChildren : public NodeImpl, } // if ... checkCanAdd(newChild); - typename std::deque::iterator result = findChild(oldChild); removeIfRequired(newChild); + typename std::deque::iterator result = findChild(oldChild); *result = newChild; newChild->setParentNode(this); diff --git a/include/DOM/Text.hpp b/include/DOM/Text.hpp index 020d4ecf..a9c3d471 100644 --- a/include/DOM/Text.hpp +++ b/include/DOM/Text.hpp @@ -28,6 +28,8 @@ class Text : public CharacterData Text(const Text& rhs) : CharacterDataT(rhs) { } explicit Text(const NodeT& rhs) : CharacterDataT(rhs, 0) { + if(NodeT::impl_ == 0) // null nodes can always be cast + return; typename Text::Type type = rhs.getNodeType(); if((type != Text::TEXT_NODE) && (type != Text::CDATA_SECTION_NODE)) //throw std::runtime_error("bad_cast: Cannot cast Node to Text");