[libxml++] Make libxml++ compatible with libxml2 usage
- From: Murray Cumming <murrayc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libxml++] Make libxml++ compatible with libxml2 usage
- Date: Sun, 14 Nov 2010 14:46:16 +0000 (UTC)
commit 752ff3b4394d334ad6ba3e38189d5898fa15c8f0
Author: Alessandro Pignotti <a pignotti sssup it>
Date: Mon Nov 8 16:25:53 2010 +0100
Make libxml++ compatible with libxml2 usage
libxml++/document.cc | 94 +++++++++++++++++-----------------
libxml++/document.h | 4 ++
libxml++/nodes/element.cc | 21 +++++++-
libxml++/nodes/node.cc | 69 ++++++++++++++-----------
libxml++/parsers/textreader.cc | 11 ++++
libxml++/validators/dtdvalidator.cc | 9 +++-
6 files changed, 127 insertions(+), 81 deletions(-)
---
diff --git a/libxml++/document.cc b/libxml++/document.cc
index 0474a38..2056d3e 100644
--- a/libxml++/document.cc
+++ b/libxml++/document.cc
@@ -26,14 +26,17 @@
#include <iostream>
-namespace
+namespace xmlpp
{
-//Called by libxml whenever it constructs something,
-//such as a node or attribute.
-//This allows us to create a C++ instance for every C instance.
-void on_libxml_construct(xmlNode* node)
+void Document::create_wrapper(xmlNode* node)
{
+ if(node->_private)
+ {
+ //Node already wrapped, skip
+ return;
+ }
+
switch (node->type)
{
case XML_ELEMENT_NODE:
@@ -97,51 +100,9 @@ void on_libxml_construct(xmlNode* node)
}
}
-//Called by libxml whenever it destroys something
-//such as a node or attribute.
-//This allows us to delete the C++ instance for the C instance, if any.
-void on_libxml_destruct(xmlNode* node)
-{
- bool bPrivateDeleted = false;
- if (node->type == XML_DTD_NODE)
- {
- xmlpp::Dtd* cppDtd = static_cast<xmlpp::Dtd*>(node->_private);
- if(cppDtd)
- {
- delete cppDtd;
- bPrivateDeleted = true;
- }
- }
- else if (node->type == XML_DOCUMENT_NODE)
- // do nothing. See on_libxml_construct for an explanation
- ;
- else
- {
- xmlpp::Node* cppNode = static_cast<xmlpp::Node*>(node->_private);
- if(cppNode)
- {
- delete cppNode;
- bPrivateDeleted = true;
- }
- }
-
- //This probably isn't necessary:
- if(bPrivateDeleted)
- node->_private = 0;
-}
-
-} //anonymous namespace
-
-namespace xmlpp
-{
-
Document::Init::Init()
{
xmlInitParser(); //Not always necessary, but necessary for thread safety.
- xmlRegisterNodeDefault(on_libxml_construct);
- xmlDeregisterNodeDefault(on_libxml_destruct);
- xmlThrDefRegisterNodeDefault(on_libxml_construct);
- xmlThrDefDeregisterNodeDefault(on_libxml_destruct);
}
Document::Init::~Init()
@@ -174,9 +135,44 @@ Document::Document(xmlDoc* doc)
Document::~Document()
{
+ free_wrappers(reinterpret_cast<xmlNode*>(impl_));
xmlFreeDoc(impl_);
}
+void Document::free_wrappers(xmlNode* node)
+{
+ //Walk the children list
+ for(xmlNode* child=node->children; child; child=child->next)
+ free_wrappers(child);
+
+ //Delete the local one
+ switch(node->type)
+ {
+ //Node types that have no properties
+ case XML_DTD_NODE:
+ delete static_cast<Dtd*>(node->_private);
+ node->_private=0;
+ return;
+ case XML_ATTRIBUTE_NODE:
+ case XML_ELEMENT_DECL:
+ case XML_ATTRIBUTE_DECL:
+ case XML_ENTITY_DECL:
+ delete static_cast<Node*>(node->_private);
+ node->_private=0;
+ return;
+ case XML_DOCUMENT_NODE:
+ //Do not free now, the ownernship is reversed
+ return;
+ default:
+ delete static_cast<Node*>(node->_private);
+ node->_private=0;
+ }
+
+ //Walk the attributes list
+ for(xmlAttr* attr=node->properties; attr; attr=attr->next)
+ free_wrappers(reinterpret_cast<xmlNode*>(attr));
+}
+
Glib::ustring Document::get_encoding() const
{
Glib::ustring encoding;
@@ -217,7 +213,10 @@ Element* Document::get_root_node() const
if(root == 0)
return 0;
else
+ {
+ create_wrapper(root);
return reinterpret_cast<Element*>(root->_private);
+ }
}
Element* Document::create_root_node(const Glib::ustring& name,
@@ -271,6 +270,7 @@ CommentNode* Document::add_comment(const Glib::ustring& content)
// Use the result, because node can be freed when merging text nodes:
node = xmlAddChild( (xmlNode*)impl_, node);
+ create_wrapper(node);
return static_cast<CommentNode*>(node->_private);
}
diff --git a/libxml++/document.h b/libxml++/document.h
index c30068c..0ed9e7b 100644
--- a/libxml++/document.h
+++ b/libxml++/document.h
@@ -170,6 +170,10 @@ public:
///Access the underlying libxml implementation.
const _xmlDoc* cobj() const;
+ ///Construct the right C++ instances for a given element
+ static void create_wrapper(_xmlNode* node);
+ ///Recursively destroy the created C++ instances
+ static void free_wrappers(_xmlNode* attr);
protected:
/** Retrieve an Entity.
* The entity can be from an external subset or internally declared.
diff --git a/libxml++/nodes/element.cc b/libxml++/nodes/element.cc
index 69604f5..e275e71 100644
--- a/libxml++/nodes/element.cc
+++ b/libxml++/nodes/element.cc
@@ -7,6 +7,7 @@
#include <libxml++/nodes/element.h>
#include <libxml++/nodes/textnode.h>
#include <libxml++/exceptions/internal_error.h>
+#include <libxml++/document.h>
#include <libxml/tree.h>
@@ -25,6 +26,7 @@ Element::AttributeList Element::get_attributes()
AttributeList attributes;
for(xmlAttr* attr = cobj()->properties; attr; attr = attr->next)
{
+ Document::create_wrapper(reinterpret_cast<xmlNode*>(attr));
attributes.push_back(reinterpret_cast<Attribute*>(attr->_private));
}
@@ -44,6 +46,7 @@ Attribute* Element::get_attribute(const Glib::ustring& name,
xmlAttr* attr = xmlHasProp(const_cast<xmlNode*>(cobj()), (const xmlChar*)name.c_str());
if( attr )
{
+ Document::create_wrapper(reinterpret_cast<xmlNode*>(attr));
return reinterpret_cast<Attribute*>(attr->_private);
}
}
@@ -54,6 +57,7 @@ Attribute* Element::get_attribute(const Glib::ustring& name,
(const xmlChar*)ns_uri.c_str());
if( attr )
{
+ Document::create_wrapper(reinterpret_cast<xmlNode*>(attr));
return reinterpret_cast<Attribute*>(attr->_private);
}
}
@@ -95,7 +99,10 @@ Attribute* Element::set_attribute(const Glib::ustring& name, const Glib::ustring
}
if(attr)
+ {
+ Document::create_wrapper(reinterpret_cast<xmlNode*>(attr));
return reinterpret_cast<Attribute*>(attr->_private);
+ }
else
return 0;
}
@@ -117,7 +124,10 @@ const TextNode* Element::get_child_text() const
// FIXME: return only the first content node
for(xmlNode* child = cobj()->children; child; child = child->next)
if(child->type == XML_TEXT_NODE)
- return static_cast<TextNode*>(child->_private);
+ {
+ Document::create_wrapper(child);
+ return static_cast<TextNode*>(child->_private);
+ }
return 0;
}
@@ -128,7 +138,10 @@ TextNode* Element::get_child_text()
// What should we do instead? Update the documentation if we change this. murrayc.
for(xmlNode* child = cobj()->children; child; child = child->next)
if(child->type == XML_TEXT_NODE)
- return static_cast<TextNode*>(child->_private);
+ {
+ Document::create_wrapper(child);
+ return static_cast<TextNode*>(child->_private);
+ }
return 0;
}
@@ -151,6 +164,7 @@ TextNode* Element::add_child_text(const Glib::ustring& content)
// Use the result, because node can be freed when merging text nodes:
node = xmlAddChild(cobj(), node);
+ Document::create_wrapper(node);
return static_cast<TextNode*>(node->_private);
}
return 0;
@@ -168,6 +182,7 @@ TextNode* Element::add_child_text(xmlpp::Node* previous_sibling, const Glib::ust
// Use the result, because node can be freed when merging text nodes:
node = xmlAddNextSibling(previous_sibling->cobj(), node);
+ Document::create_wrapper(node);
return static_cast<TextNode*>(node->_private);
}
return 0;
@@ -185,6 +200,7 @@ TextNode* Element::add_child_text_before(xmlpp::Node* next_sibling, const Glib::
// Use the result, because node can be freed when merging text nodes:
node = xmlAddPrevSibling(next_sibling->cobj(), node);
+ Document::create_wrapper(node);
return static_cast<TextNode*>(node->_private);
}
return 0;
@@ -226,6 +242,7 @@ CommentNode* Element::add_child_comment(const Glib::ustring& content)
// Use the result, because node can be freed when merging text nodes:
node = xmlAddChild(cobj(), node);
+ Document::create_wrapper(node);
return static_cast<CommentNode*>(node->_private);
}
diff --git a/libxml++/nodes/node.cc b/libxml++/nodes/node.cc
index 7cf34d3..e9ba6dc 100644
--- a/libxml++/nodes/node.cc
+++ b/libxml++/nodes/node.cc
@@ -7,6 +7,7 @@
#include <libxml++/nodes/element.h>
#include <libxml++/nodes/node.h>
#include <libxml++/exceptions/internal_error.h>
+#include <libxml++/document.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
#include <libxml/tree.h>
@@ -32,8 +33,11 @@ const Element* Node::get_parent() const
Element* Node::get_parent()
{
- return cobj()->parent && cobj()->parent->type == XML_ELEMENT_NODE ?
- static_cast<Element*>(cobj()->parent->_private) : 0;
+ if(!(cobj()->parent && cobj()->parent->type == XML_ELEMENT_NODE))
+ return 0;
+
+ Document::create_wrapper(cobj()->parent);
+ return static_cast<Element*>(cobj()->parent->_private);
}
const Node* Node::get_next_sibling() const
@@ -43,8 +47,11 @@ const Node* Node::get_next_sibling() const
Node* Node::get_next_sibling()
{
- return cobj()->next ?
- static_cast<Node*>(cobj()->next->_private) : 0;
+ if(!cobj()->next)
+ return 0;
+
+ Document::create_wrapper(cobj()->next);
+ return static_cast<Node*>(cobj()->next->_private);
}
const Node* Node::get_previous_sibling() const
@@ -54,8 +61,11 @@ const Node* Node::get_previous_sibling() const
Node* Node::get_previous_sibling()
{
- return cobj()->prev ?
- static_cast<Node*>(cobj()->prev->_private) : 0;
+ if(!cobj()->prev)
+ return 0;
+
+ Document::create_wrapper(cobj()->prev);
+ return static_cast<Node*>(cobj()->prev->_private);
}
Node::NodeList Node::get_children(const Glib::ustring& name)
@@ -67,20 +77,10 @@ Node::NodeList Node::get_children(const Glib::ustring& name)
NodeList children;
do
{
- if(child->_private)
- {
- if(name.empty() || name == (const char*)child->name)
- children.push_back(reinterpret_cast<Node*>(child->_private));
- }
- else
+ if(name.empty() || name == (const char*)child->name)
{
- //This should not happen:
- //This is for debugging only:
- //if(child->type == XML_ENTITY_DECL)
- //{
- // xmlEntity* centity = (xmlEntity*)child;
- // std::cerr << "Node::get_children(): unexpected unwrapped Entity Declaration node name =" << centity->name << std::endl;
- //}
+ Document::create_wrapper(child);
+ children.push_back(reinterpret_cast<Node*>(child->_private));
}
}
while((child = child->next));
@@ -101,10 +101,11 @@ Element* Node::add_child(const Glib::ustring& name,
return 0;
_xmlNode* node = xmlAddChild(impl_, child);
- if(node)
- return static_cast<Element*>(node->_private);
- else
- return 0;
+ if(!node)
+ return 0;
+
+ Document::create_wrapper(node);
+ return static_cast<Element*>(node->_private);
}
Element* Node::add_child(xmlpp::Node* previous_sibling,
@@ -119,10 +120,11 @@ Element* Node::add_child(xmlpp::Node* previous_sibling,
return 0;
_xmlNode* node = xmlAddNextSibling(previous_sibling->cobj(), child);
- if(node)
- return static_cast<Element*>(node->_private);
- else
- return 0;
+ if(!node)
+ return 0;
+
+ Document::create_wrapper(node);
+ return static_cast<Element*>(node->_private);
}
Element* Node::add_child_before(xmlpp::Node* next_sibling,
@@ -137,10 +139,11 @@ Element* Node::add_child_before(xmlpp::Node* next_sibling,
return 0;
_xmlNode* node = xmlAddPrevSibling(next_sibling->cobj(), child);
- if(node)
- return static_cast<Element*>(node->_private);
- else
- return 0;
+ if(!node)
+ return 0;
+
+ Document::create_wrapper(node);
+ return static_cast<Element*>(node->_private);
}
_xmlNode* Node::create_new_child_node(const Glib::ustring& name, const Glib::ustring& ns_prefix)
@@ -179,6 +182,7 @@ void Node::remove_child(Node* node)
{
//TODO: Allow a node to be removed without deleting it, to allow it to be moved?
//This would require a more complex memory management API.
+ Document::free_wrappers(node->cobj());
xmlUnlinkNode(node->cobj());
xmlFreeNode(node->cobj()); //The C++ instance will be deleted in a callback.
}
@@ -200,6 +204,7 @@ Node* Node::import_node(const Node* node, bool recursive)
xmlNode* added_node = xmlAddChild(this->cobj(),imported_node);
if (!added_node)
{
+ Document::free_wrappers(imported_node);
xmlFreeNode(imported_node);
#ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
@@ -209,6 +214,7 @@ Node* Node::import_node(const Node* node, bool recursive)
#endif //LIBXMLCPP_EXCEPTIONS_ENABLED
}
+ Document::create_wrapper(imported_node);
return static_cast<Node*>(imported_node->_private);
}
@@ -292,6 +298,7 @@ static NodeSet find_impl(xmlXPathContext* ctxt, const Glib::ustring& xpath)
//TODO: Check for other cnode->type values?
+ Document::create_wrapper(cnode);
Node* cppNode = static_cast<Node*>(cnode->_private);
nodes.push_back(cppNode);
}
diff --git a/libxml++/parsers/textreader.cc b/libxml++/parsers/textreader.cc
index a0b71c6..8770771 100644
--- a/libxml++/parsers/textreader.cc
+++ b/libxml++/parsers/textreader.cc
@@ -2,6 +2,7 @@
#include <libxml++/exceptions/internal_error.h>
#include <libxml++/exceptions/parse_error.h>
#include <libxml++/exceptions/validity_error.h>
+#include <libxml++/document.h>
#include <libxml/xmlreader.h>
@@ -298,7 +299,10 @@ Node* TextReader::get_current_node()
{
xmlNodePtr node = xmlTextReaderCurrentNode(impl_);
if(node)
+ {
+ Document::create_wrapper(node);
return static_cast<Node*>(node->_private);
+ }
check_for_exceptions();
return 0;
@@ -308,7 +312,10 @@ const Node* TextReader::get_current_node() const
{
xmlNodePtr node = xmlTextReaderCurrentNode(impl_);
if(node)
+ {
+ Document::create_wrapper(node);
return static_cast<Node*>(node->_private);
+ }
check_for_exceptions();
return 0;
@@ -328,7 +335,11 @@ Node* TextReader::expand()
{
xmlNodePtr node = xmlTextReaderExpand(impl_);
if(node)
+ if(node)
+ {
+ Document::create_wrapper(node);
return static_cast<Node*>(node->_private);
+ }
check_for_exceptions();
return 0;
diff --git a/libxml++/validators/dtdvalidator.cc b/libxml++/validators/dtdvalidator.cc
index 7d7d200..9d9420a 100644
--- a/libxml++/validators/dtdvalidator.cc
+++ b/libxml++/validators/dtdvalidator.cc
@@ -13,6 +13,7 @@
#include "libxml++/keepblanks.h"
#include "libxml++/exceptions/internal_error.h"
#include "libxml++/io/istreamparserinputbuffer.h"
+#include "libxml++/document.h"
#include <libxml/parserInternals.h>//For xmlCreateFileParserCtxt().
@@ -67,6 +68,7 @@ void DtdValidator::parse_subset(const Glib::ustring& external,const Glib::ustrin
#endif //LIBXMLCPP_EXCEPTIONS_ENABLED
}
+ Document::create_wrapper(reinterpret_cast<xmlNode*>(dtd));
dtd_ = static_cast<Dtd*>(dtd->_private);
}
@@ -95,6 +97,7 @@ void DtdValidator::parse_stream(std::istream& in)
#endif //LIBXMLCPP_EXCEPTIONS_ENABLED
}
+ Document::create_wrapper(reinterpret_cast<xmlNode*>(dtd));
dtd_ = static_cast<Dtd*>(dtd->_private);
}
@@ -102,7 +105,11 @@ void DtdValidator::release_underlying()
{
if(dtd_)
{
- xmlFreeDtd(dtd_->cobj());
+ //Make a local copy as the wrapper is destroyed first
+ //After free_wrappers is called dtd_ will be invalid (e.g. delete dtd_)
+ xmlDtd* dtd=dtd_->cobj();
+ Document::free_wrappers(reinterpret_cast<xmlNode*>(dtd));
+ xmlFreeDtd(dtd);
dtd_ = 0;
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]