Avoid assert() when loading xml: Throw an XMLerror if attribute_value fails.
[ardour.git] / libs / pbd / xml++.cc
index 2db08eb3e2cc4eb699e17f212fb93aaeb9f4c3bb..c18d36f065addd195ca543ca4f8e053c011aa274 100644 (file)
@@ -120,7 +120,7 @@ XMLTree::read_internal(bool validate)
 }
 
 bool
-XMLTree::read_buffer(const string& buffer)
+XMLTree::read_buffer(const string& buffer, bool to_tree_doc)
 {
        xmlDocPtr doc;
 
@@ -135,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;
 }
@@ -215,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)
@@ -226,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;
 }
 
@@ -245,7 +257,6 @@ XMLNode::clear_lists ()
        XMLPropertyIterator curprop;
 
        _selected_children.clear ();
-       _propmap.clear ();
 
        for (curchild = _children.begin(); curchild != _children.end(); ++curchild) {
                delete *curchild;
@@ -275,7 +286,7 @@ XMLNode::operator= (const XMLNode& from)
        const XMLPropertyList& props = from.properties ();
 
        for (XMLPropertyConstIterator prop_iter = props.begin (); prop_iter != props.end (); ++prop_iter) {
-               add_property ((*prop_iter)->name ().c_str (), (*prop_iter)->value ());
+               set_property ((*prop_iter)->name ().c_str (), (*prop_iter)->value ());
        }
 
        const XMLNodeList& nodes = from.children ();
@@ -455,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();
 }
 
@@ -469,115 +486,126 @@ XMLNode::add_content(const string& c)
 }
 
 XMLProperty const *
-XMLNode::property(const char* n) const
+XMLNode::property(const char* name) const
 {
-       string ns(n);
-       map<string,XMLProperty*>::const_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 const *
-XMLNode::property(const string& ns) const
+XMLNode::property(const string& name) const
 {
-       map<string,XMLProperty*>::const_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 char* n)
+XMLNode::property(const char* name)
 {
-       string ns(n);
-       map<string,XMLProperty*>::iterator iter;
+       XMLPropertyIterator 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)
+XMLNode::property(const string& name)
 {
-       map<string,XMLProperty*>::iterator iter;
+       XMLPropertyIterator 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;
 }
 
 bool
-XMLNode::has_property_with_value (const string& key, const string& value) const
+XMLNode::has_property_with_value (const string& name, const string& value) const
 {
-       map<string,XMLProperty*>::const_iterator iter = _propmap.find(key);
-       if (iter != _propmap.end()) {
-               const XMLProperty* p = (iter->second);
-               return (p && p->value() == value);
+       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 string& v)
+bool
+XMLNode::set_property(const char* name, const string& value)
 {
-       string ns(n);
-        map<string,XMLProperty*>::iterator iter;
+       XMLPropertyIterator iter = _proplist.begin();
 
-        if ((iter = _propmap.find(ns)) != _propmap.end()) {
-                iter->second->set_value (v);
-                return iter->second;
+       while (iter != _proplist.end()) {
+               if ((*iter)->name() == name) {
+                       (*iter)->set_value (value);
+                       return *iter;
+               }
+               ++iter;
        }
 
-       XMLProperty* tmp = new XMLProperty(ns, v);
+       XMLProperty* new_property = new XMLProperty(name, value);
 
-       if (!tmp) {
+       if (!new_property) {
                return 0;
        }
 
-       _propmap[tmp->name()] = tmp;
-       _proplist.insert(_proplist.end(), tmp);
+       _proplist.insert(_proplist.end(), new_property);
 
-       return tmp;
+       return new_property;
 }
 
-XMLProperty*
-XMLNode::add_property(const char* n, const char* v)
+bool
+XMLNode::get_property(const char* name, std::string& value) const
 {
-       string vs(v);
-       return add_property(n, vs);
-}
+       XMLProperty const* const prop = property (name);
+       if (!prop)
+               return false;
 
-XMLProperty*
-XMLNode::add_property(const char* name, const long value)
-{
-       char str[64];
-       snprintf(str, sizeof(str), "%ld", value);
-       return add_property(name, str);
+       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];
-               XMLPropertyIterator i = std::find(_proplist.begin(), _proplist.end(), p);
-               if (i != _proplist.end ()) {
-                       _proplist.erase (i);
+       XMLPropertyIterator iter = _proplist.begin();
+
+       while (iter != _proplist.end()) {
+               if ((*iter)->name() == name) {
+                       XMLProperty* property = *iter;
+                       _proplist.erase (iter);
+                       delete property;
+                       break;
                }
-               delete p;
-               _propmap.erase(n);
+               ++iter;
        }
 }
 
@@ -636,16 +664,26 @@ XMLNode::remove_nodes_and_delete(const string& propname, const string& val)
        }
 }
 
+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;
+                       }
+               }
+       }
+}
+
 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()
@@ -671,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) {