X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fpbd%2Fxml%2B%2B.cc;h=c18d36f065addd195ca543ca4f8e053c011aa274;hb=c83ba533990f15c95b167d5f6e5b4762966d050d;hp=69187995a17fa31ca092d0e2e17990c3597ce46b;hpb=e279b9892b467aa823e253d97b6e9504cca0e252;p=ardour.git diff --git a/libs/pbd/xml++.cc b/libs/pbd/xml++.cc index 69187995a1..c18d36f065 100644 --- a/libs/pbd/xml++.cc +++ b/libs/pbd/xml++.cc @@ -6,7 +6,10 @@ */ #include + +#include "pbd/stacktrace.h" #include "pbd/xml++.h" + #include #include #include @@ -42,7 +45,7 @@ XMLTree::XMLTree(const XMLTree* from) , _doc (xmlCopyDoc (from->_doc, 1)) , _compression(from->compression()) { - + } XMLTree::~XMLTree() @@ -82,26 +85,23 @@ XMLTree::read_internal(bool validate) _doc = 0; } - xmlParserCtxtPtr ctxt = NULL; /* the parser context */ + /* create a parser context */ + xmlParserCtxtPtr ctxt = xmlNewParserCtxt(); + if (ctxt == NULL) { + return false; + } xmlKeepBlanksDefault(0); /* parse the file, activating the DTD validation option */ if (validate) { - /* create a parser context */ - ctxt = xmlNewParserCtxt(); - if (ctxt == NULL) { - return false; - } _doc = xmlCtxtReadFile(ctxt, _filename.c_str(), NULL, XML_PARSE_DTDVALID); } else { - _doc = xmlParseFile(_filename.c_str()); + _doc = xmlCtxtReadFile(ctxt, _filename.c_str(), NULL, XML_PARSE_HUGE); } - + /* check if parsing suceeded */ if (_doc == NULL) { - if (validate) { - xmlFreeParserCtxt(ctxt); - } + xmlFreeParserCtxt(ctxt); return false; } else { /* check if validation suceeded */ @@ -114,15 +114,13 @@ XMLTree::read_internal(bool validate) _root = readnode(xmlDocGetRootElement(_doc)); /* free up the parser context */ - if (validate) { - xmlFreeParserCtxt(ctxt); - } - + xmlFreeParserCtxt(ctxt); + return true; } bool -XMLTree::read_buffer(const string& buffer) +XMLTree::read_buffer(const string& buffer, bool to_tree_doc) { xmlDocPtr doc; @@ -137,7 +135,14 @@ XMLTree::read_buffer(const string& buffer) } _root = readnode(xmlDocGetRootElement(doc)); - xmlFreeDoc(doc); + if (to_tree_doc) { + if (_doc) { + xmlFreeDoc (_doc); + } + _doc = doc; + } else { + xmlFreeDoc (doc); + } return true; } @@ -155,6 +160,20 @@ XMLTree::write() const 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) { @@ -203,10 +222,13 @@ XMLTree::write_buffer() const return retval; } +static const int PROPERTY_RESERVE_COUNT = 16; + XMLNode::XMLNode(const string& n) : _name(n) , _is_content(false) { + _proplist.reserve (PROPERTY_RESERVE_COUNT); } XMLNode::XMLNode(const string& n, const string& c) @@ -214,10 +236,12 @@ XMLNode::XMLNode(const string& n, const string& c) , _is_content(true) , _content(c) { + _proplist.reserve (PROPERTY_RESERVE_COUNT); } XMLNode::XMLNode(const XMLNode& from) { + _proplist.reserve (PROPERTY_RESERVE_COUNT); *this = from; } @@ -233,7 +257,6 @@ XMLNode::clear_lists () XMLPropertyIterator curprop; _selected_children.clear (); - _propmap.clear (); for (curchild = _children.begin(); curchild != _children.end(); ++curchild) { delete *curchild; @@ -248,33 +271,94 @@ XMLNode::clear_lists () _proplist.clear (); } -XMLNode& +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()); + if (&from == this) { + return *this; + } + + clear_lists (); + + _name = from.name (); + set_content (from.content ()); + + const XMLPropertyList& props = from.properties (); + + for (XMLPropertyConstIterator prop_iter = props.begin (); prop_iter != props.end (); ++prop_iter) { + set_property ((*prop_iter)->name ().c_str (), (*prop_iter)->value ()); + } + + const XMLNodeList& nodes = from.children (); + for (XMLNodeConstIterator child_iter = nodes.begin (); child_iter != nodes.end (); ++child_iter) { + add_child_copy (**child_iter); + } + + return *this; +} + +bool +XMLNode::operator== (const XMLNode& other) const +{ + if (is_content () != other.is_content ()) { + return false; + } + + if (is_content ()) { + if (content () != other.content ()) { + return false; } - - nodes = from.children(); - for (curnode = nodes.begin(); curnode != nodes.end(); ++curnode) { - add_child_copy(**curnode); + } else { + if (name () != other.name ()) { + return false; } } - return *this; + XMLPropertyList const& other_properties = other.properties (); + + if (_proplist.size () != other_properties.size ()) { + return false; + } + + XMLPropertyConstIterator our_prop_iter = _proplist.begin(); + XMLPropertyConstIterator other_prop_iter = other_properties.begin(); + + while (our_prop_iter != _proplist.end ()) { + XMLProperty const* our_prop = *our_prop_iter; + XMLProperty const* other_prop = *other_prop_iter; + if (our_prop->name () != other_prop->name () || our_prop->value () != other_prop->value ()) { + return false; + } + ++our_prop_iter; + ++other_prop_iter; + } + + XMLNodeList const& other_children = other.children(); + + if (_children.size() != other_children.size()) { + return false; + } + + XMLNodeConstIterator our_child_iter = _children.begin (); + XMLNodeConstIterator other_child_iter = other_children.begin (); + + while (our_child_iter != _children.end()) { + XMLNode const* our_child = *our_child_iter; + XMLNode const* other_child = *other_child_iter; + + if (*our_child != *other_child) { + return false; + } + ++our_child_iter; + ++other_child_iter; + } + return true; +} + +bool +XMLNode::operator!= (const XMLNode& other) const +{ + return !(*this == other); } const string& @@ -366,10 +450,10 @@ XMLTree::find(const string xpath, XMLNode* node) const } else { ctxt = xmlXPathNewContext(_doc); } - + boost::shared_ptr result = boost::shared_ptr(find_impl(ctxt, xpath)); - + xmlXPathFreeContext(ctxt); if (doc) { xmlFreeDoc (doc); @@ -382,10 +466,16 @@ std::string XMLNode::attribute_value() { XMLNodeList children = this->children(); - assert(!_is_content); - assert(children.size() == 1); + if (_is_content) + throw XMLException("XMLNode: attribute_value failed (is_content) for requested node: " + name()); + + if (children.size() != 1) + throw XMLException("XMLNode: attribute_value failed (children.size != 1) for requested node: " + name()); + XMLNode* child = *(children.begin()); - assert(child->is_content()); + if (!child->is_content()) + throw XMLException("XMLNode: attribute_value failed (!child->is_content()) for requested node: " + name()); + return child->content(); } @@ -395,77 +485,127 @@ XMLNode::add_content(const string& c) return add_child_copy(XMLNode (string(), c)); } -XMLProperty* -XMLNode::property(const char* n) +XMLProperty const * +XMLNode::property(const char* name) const { - string ns(n); - map::iterator iter; + XMLPropertyConstIterator iter = _proplist.begin(); - if ((iter = _propmap.find(ns)) != _propmap.end()) { - return iter->second; + while (iter != _proplist.end()) { + if ((*iter)->name() == name) { + return *iter; + } + ++iter; } return 0; } -XMLProperty* -XMLNode::property(const string& ns) +XMLProperty const * +XMLNode::property(const string& name) const { - map::iterator iter; + XMLPropertyConstIterator iter = _proplist.begin(); - if ((iter = _propmap.find(ns)) != _propmap.end()) { - return iter->second; + while (iter != _proplist.end()) { + if ((*iter)->name() == name) { + return *iter; + } + ++iter; } - return 0; } -XMLProperty* -XMLNode::add_property(const char* n, const string& v) +XMLProperty * +XMLNode::property(const char* name) { - string ns(n); - map::iterator iter; - - if ((iter = _propmap.find(ns)) != _propmap.end()) { - iter->second->set_value (v); - return iter->second; + XMLPropertyIterator iter = _proplist.begin(); + + while (iter != _proplist.end()) { + if ((*iter)->name() == name) { + return *iter; + } + ++iter; } + return 0; +} - XMLProperty* tmp = new XMLProperty(ns, v); +XMLProperty * +XMLNode::property(const string& name) +{ + XMLPropertyIterator iter = _proplist.begin(); - if (!tmp) { - return 0; + while (iter != _proplist.end()) { + if ((*iter)->name() == name) { + return *iter; + } + ++iter; } - _propmap[tmp->name()] = tmp; - _proplist.insert(_proplist.end(), tmp); + return 0; +} - return tmp; +bool +XMLNode::has_property_with_value (const string& name, const string& value) const +{ + XMLPropertyConstIterator iter = _proplist.begin(); + + while (iter != _proplist.end()) { + if ((*iter)->name() == name && (*iter)->value() == value) { + return true; + } + ++iter; + } + return false; } -XMLProperty* -XMLNode::add_property(const char* n, const char* v) +bool +XMLNode::set_property(const char* name, const string& value) { - string vs(v); - return add_property(n, vs); + XMLPropertyIterator iter = _proplist.begin(); + + while (iter != _proplist.end()) { + if ((*iter)->name() == name) { + (*iter)->set_value (value); + return *iter; + } + ++iter; + } + + XMLProperty* new_property = new XMLProperty(name, value); + + if (!new_property) { + return 0; + } + + _proplist.insert(_proplist.end(), new_property); + + return new_property; } -XMLProperty* -XMLNode::add_property(const char* name, const long value) +bool +XMLNode::get_property(const char* name, std::string& value) const { - char str[64]; - snprintf(str, sizeof(str), "%ld", value); - return add_property(name, str); + XMLProperty const* const prop = property (name); + if (!prop) + return false; + + value = prop->value (); + + return true; } void -XMLNode::remove_property(const string& n) +XMLNode::remove_property(const string& name) { - if (_propmap.find(n) != _propmap.end()) { - XMLProperty* p = _propmap[n]; - _proplist.remove (p); - delete p; - _propmap.erase(n); + XMLPropertyIterator iter = _proplist.begin(); + + while (iter != _proplist.end()) { + if ((*iter)->name() == name) { + XMLProperty* property = *iter; + _proplist.erase (iter); + delete property; + break; + } + ++iter; } } @@ -483,15 +623,12 @@ void XMLNode::remove_nodes(const string& n) { XMLNodeIterator i = _children.begin(); - XMLNodeIterator tmp; - while (i != _children.end()) { - tmp = i; - ++tmp; if ((*i)->name() == n) { - _children.erase (i); + i = _children.erase (i); + } else { + ++i; } - i = tmp; } } @@ -499,16 +636,14 @@ void XMLNode::remove_nodes_and_delete(const string& n) { XMLNodeIterator i = _children.begin(); - XMLNodeIterator tmp; while (i != _children.end()) { - tmp = i; - ++tmp; if ((*i)->name() == n) { delete *i; - _children.erase (i); + i = _children.erase (i); + } else { + ++i; } - i = tmp; } } @@ -516,20 +651,32 @@ void XMLNode::remove_nodes_and_delete(const string& propname, const string& val) { XMLNodeIterator i = _children.begin(); - XMLNodeIterator tmp; - XMLProperty* prop; + XMLProperty const * prop; while (i != _children.end()) { - tmp = i; - ++tmp; - prop = (*i)->property(propname); if (prop && prop->value() == val) { delete *i; - _children.erase(i); + i = _children.erase(i); + } else { + ++i; } + } +} - i = tmp; +void +XMLNode::remove_node_and_delete(const string& n, const string& propname, + const string& val) +{ + for (XMLNodeIterator i = _children.begin(); i != _children.end(); ++i) { + if ((*i)->name() == n) { + XMLProperty const * prop = (*i)->property (propname); + if (prop && prop->value() == val) { + delete *i; + _children.erase (i); + break; + } + } } } @@ -537,12 +684,6 @@ XMLProperty::XMLProperty(const string& n, const string& v) : _name(n) , _value(v) { - // Normalize property name (replace '_' with '-' as old session are inconsistent) - for (size_t i = 0; i < _name.length(); ++i) { - if (_name[i] == '_') { - _name[i] = '-'; - } - } } XMLProperty::~XMLProperty() @@ -568,7 +709,7 @@ readnode(xmlNodePtr node) if (attr->children) { content = (char*)attr->children->content; } - tmp->add_property((const char*)attr->name, content); + tmp->set_property((const char*)attr->name, content); } if (node->content) { @@ -587,10 +728,6 @@ readnode(xmlNodePtr node) static void writenode(xmlDocPtr doc, XMLNode* n, xmlNodePtr p, int root = 0) { - XMLPropertyList props; - XMLPropertyIterator curprop; - XMLNodeList children; - XMLNodeIterator curchild; xmlNodePtr node; if (root) { @@ -604,14 +741,18 @@ writenode(xmlDocPtr doc, XMLNode* n, xmlNodePtr p, int root = 0) xmlNodeSetContentLen(node, (const xmlChar*)n->content().c_str(), n->content().length()); } - props = n->properties(); - for (curprop = props.begin(); curprop != props.end(); ++curprop) { - xmlSetProp(node, (const xmlChar*) (*curprop)->name().c_str(), (const xmlChar*) (*curprop)->value().c_str()); + const XMLPropertyList& props = n->properties(); + + for (XMLPropertyConstIterator prop_iter = props.begin (); prop_iter != props.end (); + ++prop_iter) { + xmlSetProp (node, (const xmlChar*)(*prop_iter)->name ().c_str (), + (const xmlChar*)(*prop_iter)->value ().c_str ()); } - children = n->children(); - for (curchild = children.begin(); curchild != children.end(); ++curchild) { - writenode(doc, *curchild, node); + const XMLNodeList& children = n->children (); + for (XMLNodeConstIterator child_iter = children.begin (); child_iter != children.end (); + ++child_iter) { + writenode (doc, *child_iter, node); } } @@ -662,11 +803,11 @@ XMLNode::dump (ostream& s, string p) const 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"; } }