X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=libs%2Fpbd%2Fxml%2B%2B.cc;h=5fb777bdc77444b6c989dc0548c4c9fdc7097242;hb=6990c31ed52c1c2491c19fc68c402acb4abc10e8;hp=90d7c3cf4879720fd523fcdea47e3037b3162af1;hpb=271f298635567b7aef922316e14b910fda0c508e;p=ardour.git diff --git a/libs/pbd/xml++.cc b/libs/pbd/xml++.cc index 90d7c3cf48..5fb777bdc7 100644 --- a/libs/pbd/xml++.cc +++ b/libs/pbd/xml++.cc @@ -5,12 +5,13 @@ * Modified for Ardour and released under the same terms. */ +#include #include "pbd/xml++.h" #include #include #include -#define XML_VERSION "1.0" +xmlChar* xml_version = xmlCharStrdup("1.0"); using namespace std; @@ -21,6 +22,7 @@ static XMLSharedNodeList* find_impl(xmlXPathContext* ctxt, const string& xpath); XMLTree::XMLTree() : _filename() , _root(0) + , _doc (0) , _compression(0) { } @@ -28,6 +30,7 @@ XMLTree::XMLTree() XMLTree::XMLTree(const string& fn, bool validate) : _filename(fn) , _root(0) + , _doc (0) , _compression(0) { read_internal(validate); @@ -36,13 +39,19 @@ XMLTree::XMLTree(const string& fn, bool validate) XMLTree::XMLTree(const XMLTree* from) : _filename(from->filename()) , _root(new XMLNode(*from->root())) + , _doc (xmlCopyDoc (from->_doc, 1)) , _compression(from->compression()) { + } XMLTree::~XMLTree() { delete _root; + + if (_doc) { + xmlFreeDoc (_doc); + } } int @@ -68,8 +77,12 @@ XMLTree::read_internal(bool validate) delete _root; _root = 0; + if (_doc) { + xmlFreeDoc (_doc); + _doc = 0; + } + xmlParserCtxtPtr ctxt = NULL; /* the parser context */ - xmlDocPtr doc; /* the resulting document tree */ xmlKeepBlanksDefault(0); /* parse the file, activating the DTD validation option */ @@ -79,13 +92,13 @@ XMLTree::read_internal(bool validate) if (ctxt == NULL) { return false; } - doc = xmlCtxtReadFile(ctxt, _filename.c_str(), NULL, XML_PARSE_DTDVALID); + _doc = xmlCtxtReadFile(ctxt, _filename.c_str(), NULL, XML_PARSE_DTDVALID); } else { - doc = xmlParseFile(_filename.c_str()); + _doc = xmlParseFile(_filename.c_str()); } - + /* check if parsing suceeded */ - if (doc == NULL) { + if (_doc == NULL) { if (validate) { xmlFreeParserCtxt(ctxt); } @@ -94,21 +107,17 @@ XMLTree::read_internal(bool validate) /* check if validation suceeded */ if (validate && ctxt->valid == 0) { xmlFreeParserCtxt(ctxt); - xmlFreeDoc(doc); - xmlCleanupParser(); throw XMLException("Failed to validate document " + _filename); } } - _root = readnode(xmlDocGetRootElement(doc)); + _root = readnode(xmlDocGetRootElement(_doc)); /* free up the parser context */ if (validate) { xmlFreeParserCtxt(ctxt); } - xmlFreeDoc(doc); - xmlCleanupParser(); - + return true; } @@ -122,7 +131,7 @@ XMLTree::read_buffer(const string& buffer) delete _root; _root = 0; - doc = xmlParseMemory((char*)buffer.c_str(), buffer.length()); + doc = xmlParseMemory(const_cast(buffer.c_str()), buffer.length()); if (!doc) { return false; } @@ -142,10 +151,24 @@ XMLTree::write() const int result; xmlKeepBlanksDefault(0); - doc = xmlNewDoc((xmlChar*) XML_VERSION); + doc = xmlNewDoc(xml_version); xmlSetDocCompressMode(doc, _compression); writenode(doc, _root, doc->children, 1); result = xmlSaveFormatFileEnc(_filename.c_str(), doc, "UTF-8", 1); +#ifndef NDEBUG + if (result == -1) { + xmlErrorPtr xerr = xmlGetLastError (); + if (!xerr) { + std::cerr << "unknown XML error during xmlSaveFormatFileEnc()." << std::endl; + } else { + std::cerr << "xmlSaveFormatFileEnc: error" + << " domain: " << xerr->domain + << " code: " << xerr->code + << " msg: " << xerr->message + << std::endl; + } + } +#endif xmlFreeDoc(doc); if (result == -1) { @@ -158,15 +181,17 @@ XMLTree::write() const void XMLTree::debug(FILE* out) const { +#ifdef LIBXML_DEBUG_ENABLED xmlDocPtr doc; XMLNodeList children; xmlKeepBlanksDefault(0); - doc = xmlNewDoc((xmlChar*) XML_VERSION); + doc = xmlNewDoc(xml_version); xmlSetDocCompressMode(doc, _compression); writenode(doc, _root, doc->children, 1); xmlDebugDumpDocument (out, doc); xmlFreeDoc(doc); +#endif } const string& @@ -179,7 +204,7 @@ XMLTree::write_buffer() const XMLNodeList children; xmlKeepBlanksDefault(0); - doc = xmlNewDoc((xmlChar*) XML_VERSION); + doc = xmlNewDoc(xml_version); xmlSetDocCompressMode(doc, _compression); writenode(doc, _root, doc->children, 1); xmlDocDumpMemory(doc, (xmlChar **) & ptr, &len); @@ -207,37 +232,63 @@ XMLNode::XMLNode(const string& n, const string& c) XMLNode::XMLNode(const XMLNode& from) { - XMLPropertyList props; - XMLPropertyIterator curprop; - XMLNodeList nodes; - XMLNodeIterator curnode; - - _name = from.name(); - set_content(from.content()); - - props = from.properties(); - for (curprop = props.begin(); curprop != props.end(); ++curprop) { - add_property((*curprop)->name().c_str(), (*curprop)->value()); - } - - nodes = from.children(); - for (curnode = nodes.begin(); curnode != nodes.end(); ++curnode) { - add_child_copy(**curnode); - } + *this = from; } XMLNode::~XMLNode() +{ + clear_lists (); +} + +void +XMLNode::clear_lists () { XMLNodeIterator curchild; XMLPropertyIterator curprop; + _selected_children.clear (); + _propmap.clear (); + for (curchild = _children.begin(); curchild != _children.end(); ++curchild) { delete *curchild; } + _children.clear (); + for (curprop = _proplist.begin(); curprop != _proplist.end(); ++curprop) { delete *curprop; } + + _proplist.clear (); +} + +XMLNode& +XMLNode::operator= (const XMLNode& from) +{ + if (&from != this) { + + XMLPropertyList props; + XMLPropertyIterator curprop; + XMLNodeList nodes; + XMLNodeIterator curnode; + + clear_lists (); + + _name = from.name(); + set_content(from.content()); + + props = from.properties(); + for (curprop = props.begin(); curprop != props.end(); ++curprop) { + add_property((*curprop)->name().c_str(), (*curprop)->value()); + } + + nodes = from.children(); + for (curnode = nodes.begin(); curnode != nodes.end(); ++curnode) { + add_child_copy(**curnode); + } + } + + return *this; } const string& @@ -317,17 +368,26 @@ XMLNode::add_child_copy(const XMLNode& n) } boost::shared_ptr -XMLNode::find(const string xpath) const +XMLTree::find(const string xpath, XMLNode* node) const { - xmlDocPtr doc = xmlNewDoc((xmlChar*) XML_VERSION); - writenode(doc, (XMLNode*)this, doc->children, 1); - xmlXPathContext* ctxt = xmlXPathNewContext(doc); + xmlXPathContext* ctxt; + xmlDocPtr doc = 0; + if (node) { + doc = xmlNewDoc(xml_version); + writenode(doc, node, doc->children, 1); + ctxt = xmlXPathNewContext(doc); + } else { + ctxt = xmlXPathNewContext(_doc); + } + boost::shared_ptr result = - boost::shared_ptr(find_impl(ctxt, xpath)); - + boost::shared_ptr(find_impl(ctxt, xpath)); + xmlXPathFreeContext(ctxt); - xmlFreeDoc(doc); + if (doc) { + xmlFreeDoc (doc); + } return result; } @@ -378,8 +438,11 @@ XMLProperty* XMLNode::add_property(const char* n, const string& v) { string ns(n); - if (_propmap.find(ns) != _propmap.end()) { - remove_property(ns); + map::iterator iter; + + if ((iter = _propmap.find(ns)) != _propmap.end()) { + iter->second->set_value (v); + return iter->second; } XMLProperty* tmp = new XMLProperty(ns, v); @@ -404,8 +467,8 @@ XMLNode::add_property(const char* n, const char* v) XMLProperty* XMLNode::add_property(const char* name, const long value) { - static char str[1024]; - snprintf(str, 1024, "%ld", value); + char str[64]; + snprintf(str, sizeof(str), "%ld", value); return add_property(name, str); } @@ -420,6 +483,16 @@ XMLNode::remove_property(const string& n) } } +/** Remove any property with the given name from this node and its children */ +void +XMLNode::remove_property_recursively(const string& n) +{ + remove_property (n); + for (XMLNodeIterator i = _children.begin(); i != _children.end(); ++i) { + (*i)->remove_property_recursively (n); + } +} + void XMLNode::remove_nodes(const string& n) { @@ -499,7 +572,7 @@ readnode(xmlNodePtr node) xmlAttrPtr attr; if (node->name) { - name = (char*)node->name; + name = (const char*)node->name; } tmp = new XMLNode(name); @@ -509,7 +582,7 @@ readnode(xmlNodePtr node) if (attr->children) { content = (char*)attr->children->content; } - tmp->add_property((char*)attr->name, content); + tmp->add_property((const char*)attr->name, content); } if (node->content) { @@ -535,9 +608,9 @@ writenode(xmlDocPtr doc, XMLNode* n, xmlNodePtr p, int root = 0) xmlNodePtr node; if (root) { - node = doc->children = xmlNewDocNode(doc, 0, (xmlChar*) n->name().c_str(), 0); + node = doc->children = xmlNewDocNode(doc, 0, (const xmlChar*) n->name().c_str(), 0); } else { - node = xmlNewChild(p, 0, (xmlChar*) n->name().c_str(), 0); + node = xmlNewChild(p, 0, (const xmlChar*) n->name().c_str(), 0); } if (n->is_content()) { @@ -547,7 +620,7 @@ writenode(xmlDocPtr doc, XMLNode* n, xmlNodePtr p, int root = 0) props = n->properties(); for (curprop = props.begin(); curprop != props.end(); ++curprop) { - xmlSetProp(node, (xmlChar*) (*curprop)->name().c_str(), (xmlChar*) (*curprop)->value().c_str()); + xmlSetProp(node, (const xmlChar*) (*curprop)->name().c_str(), (const xmlChar*) (*curprop)->value().c_str()); } children = n->children(); @@ -591,3 +664,23 @@ static XMLSharedNodeList* find_impl(xmlXPathContext* ctxt, const string& xpath) return nodes; } +/** Dump a node, its properties and children to a stream */ +void +XMLNode::dump (ostream& s, string p) const +{ + if (_is_content) { + s << p << " " << content() << "\n"; + } else { + s << p << "<" << _name; + for (XMLPropertyList::const_iterator i = _proplist.begin(); i != _proplist.end(); ++i) { + s << " " << (*i)->name() << "=\"" << (*i)->value() << "\""; + } + s << ">\n"; + + for (XMLNodeList::const_iterator i = _children.begin(); i != _children.end(); ++i) { + (*i)->dump (s, p + " "); + } + + s << p << "\n"; + } +}