PluginInfo::type added to copy constructor. But why is the copy constructor defined...
[ardour.git] / libs / pbd / xml++.cc
1 /* xml++.cc
2  * libxml++ and this file are copyright (C) 2000 by Ari Johnson, and
3  * are covered by the GNU Lesser General Public License, which should be
4  * included with libxml++ as the file COPYING.
5  */
6
7 #include <pbd/xml++.h>
8 #include <libxml/debugXML.h>
9
10 static XMLNode *readnode(xmlNodePtr);
11 static void writenode(xmlDocPtr, XMLNode *, xmlNodePtr, int);
12
13 XMLTree::XMLTree() 
14         : _filename(), 
15         _root(0), 
16         _compression(0)
17
18 }
19
20 XMLTree::XMLTree(const string &fn)
21         : _filename(fn), 
22         _root(0), 
23         _compression(0)
24
25         read(); 
26 }
27
28 XMLTree::XMLTree(const XMLTree * from)
29 {
30         _filename = from->filename();
31         _root = new XMLNode(*from->root());
32         _compression = from->compression();
33 }
34
35 XMLTree::~XMLTree()
36 {
37         if (_root) {
38                 delete _root;
39         }
40 }
41
42 int 
43 XMLTree::set_compression(int c)
44 {
45         if (c > 9) {
46                 c = 9;
47         } else if (c < 0) {
48                 c = 0;
49         }
50         
51         _compression = c;
52         
53         return _compression;
54 }
55
56 bool 
57 XMLTree::read(void)
58 {
59         xmlDocPtr doc;
60         
61         if (_root) {
62                 delete _root;
63                 _root = 0;
64         }
65         
66         xmlKeepBlanksDefault(0);
67         
68         doc = xmlParseFile(_filename.c_str());
69         if (!doc) {
70                 return false;
71         }
72         
73         _root = readnode(xmlDocGetRootElement(doc));
74         xmlFreeDoc(doc);
75         
76         return true;
77 }
78
79 bool 
80 XMLTree::read_buffer(const string & buffer)
81 {
82         xmlDocPtr doc;
83         
84         _filename = "";
85         
86         if (_root) {
87                 delete _root;
88                 _root = 0;
89         }
90         
91         doc = xmlParseMemory((char *) buffer.c_str(), buffer.length());
92         if (!doc) {
93                 return false;
94         }
95         
96         _root = readnode(xmlDocGetRootElement(doc));
97         xmlFreeDoc(doc);
98         
99         return true;
100 }
101
102 bool 
103 XMLTree::write(void) const
104 {
105         xmlDocPtr doc;
106         XMLNodeList children;
107         int result;
108         
109         xmlKeepBlanksDefault(0);
110         doc = xmlNewDoc((xmlChar *) "1.0");
111         xmlSetDocCompressMode(doc, _compression);
112         writenode(doc, _root, doc->children, 1);
113         result = xmlSaveFormatFileEnc(_filename.c_str(), doc, "UTF-8", 1);
114         xmlFreeDoc(doc);
115         
116         if (result == -1) {
117                 return false;
118         }
119         
120         return true;
121 }
122
123 void
124 XMLTree::debug(FILE* out) const
125 {
126     xmlDocPtr doc;
127     XMLNodeList children;
128
129     xmlKeepBlanksDefault(0);
130     doc = xmlNewDoc((xmlChar *) "1.0");
131     xmlSetDocCompressMode(doc, _compression);
132     writenode(doc, _root, doc->children, 1);
133     xmlDebugDumpDocument (out, doc);
134     xmlFreeDoc(doc);
135 }
136
137 const string & 
138 XMLTree::write_buffer(void) const
139 {
140         static string retval;
141         char *ptr;
142         int len;
143         xmlDocPtr doc;
144         XMLNodeList children;
145         
146         xmlKeepBlanksDefault(0);
147         doc = xmlNewDoc((xmlChar *) "1.0");
148         xmlSetDocCompressMode(doc, _compression);
149         writenode(doc, _root, doc->children, 1);
150         xmlDocDumpMemory(doc, (xmlChar **) & ptr, &len);
151         xmlFreeDoc(doc);
152         
153         retval = ptr;
154         
155         free(ptr);
156         
157         return retval;
158 }
159
160 XMLNode::XMLNode(const string & n)
161         :  _name(n), _is_content(false), _content(string())
162 {
163 }
164
165 XMLNode::XMLNode(const string & n, const string & c)
166         :_name(n), _is_content(true), _content(c)
167 {
168 }
169
170 XMLNode::XMLNode(const XMLNode& from)
171 {
172         XMLPropertyList props;
173         XMLPropertyIterator curprop;
174         XMLNodeList nodes;
175         XMLNodeIterator curnode;
176         
177         _name = from.name();
178         set_content(from.content());
179         
180         props = from.properties();
181         for (curprop = props.begin(); curprop != props.end(); ++curprop) {
182                 add_property((*curprop)->name().c_str(), (*curprop)->value());
183         }
184         
185         nodes = from.children();
186         for (curnode = nodes.begin(); curnode != nodes.end(); ++curnode) {
187                 add_child_copy(**curnode);
188         }
189 }
190
191 XMLNode::~XMLNode()
192 {
193         XMLNodeIterator curchild;
194         XMLPropertyIterator curprop;
195         
196         for (curchild = _children.begin(); curchild != _children.end(); ++curchild) {
197                 delete *curchild;
198         }
199             
200         for (curprop = _proplist.begin(); curprop != _proplist.end(); ++curprop) {
201                 delete *curprop;
202         }
203 }
204
205 const string & 
206 XMLNode::set_content(const string & c)
207 {
208         if (c.empty()) {
209                 _is_content = false;
210         } else {
211                 _is_content = true;
212         }
213             
214         _content = c;
215         
216         return _content;
217 }
218
219 XMLNode*
220 XMLNode::child (const char *name) const
221 {
222         /* returns first child matching name */
223
224         XMLNodeConstIterator cur;
225         
226         if (name == 0) {
227                 return 0;
228         }
229             
230         for (cur = _children.begin(); cur != _children.end(); ++cur) {
231                 if ((*cur)->name() == name) {
232                         return *cur;
233                 }
234         }
235             
236         return 0;
237 }
238
239 const XMLNodeList & 
240 XMLNode::children(const string& n) const
241 {
242         /* returns all children matching name */
243
244         XMLNodeConstIterator cur;
245         
246         if (n.empty()) {
247                 return _children;
248         }
249
250         _selected_children.clear();
251         
252         for (cur = _children.begin(); cur != _children.end(); ++cur) {
253                 if ((*cur)->name() == n) {
254                         _selected_children.insert(_selected_children.end(), *cur);
255                 }
256         }
257             
258         return _selected_children;
259 }
260
261 XMLNode *
262 XMLNode::add_child(const char * n)
263 {
264         return add_child_copy(XMLNode (n));
265 }
266
267 void
268 XMLNode::add_child_nocopy (XMLNode& n)
269 {
270         _children.insert(_children.end(), &n);
271 }
272
273 XMLNode *
274 XMLNode::add_child_copy(const XMLNode& n)
275 {
276         XMLNode *copy = new XMLNode (n);
277         _children.insert(_children.end(), copy);
278         return copy;
279 }
280
281 XMLNode *
282 XMLNode::add_content(const string & c)
283 {
284         return add_child_copy(XMLNode (string(), c));
285 }
286
287 XMLProperty *
288 XMLNode::property(const char * n)
289 {
290         string ns(n);
291         map<string,XMLProperty*>::iterator iter;
292
293         if ((iter = _propmap.find(ns)) != _propmap.end()) {
294                 return iter->second;
295         }
296
297         return 0;
298 }
299
300 XMLProperty *
301 XMLNode::property(const string & ns)
302 {
303         map<string,XMLProperty*>::iterator iter;
304
305         if ((iter = _propmap.find(ns)) != _propmap.end()) {
306                 return iter->second;
307         }
308         
309         return 0;
310 }
311
312 XMLProperty *
313 XMLNode::add_property(const char * n, const string & v)
314 {
315         string ns(n);
316         if(_propmap.find(ns) != _propmap.end()){
317                 remove_property(ns);
318         }
319
320         XMLProperty *tmp = new XMLProperty(ns, v);
321
322         if (!tmp) {
323                 return 0;
324         }
325
326         _propmap[tmp->name()] = tmp;
327         _proplist.insert(_proplist.end(), tmp);
328
329         return tmp;
330 }
331
332 XMLProperty *
333 XMLNode::add_property(const char * n, const char * v)
334 {
335         string vs(v);
336         return add_property(n, vs);
337 }
338
339 void 
340 XMLNode::remove_property(const string & n)
341 {
342         if (_propmap.find(n) != _propmap.end()) {
343                 _proplist.remove(_propmap[n]);
344                 _propmap.erase(n);
345         }
346 }
347
348 void 
349 XMLNode::remove_nodes(const string & n)
350 {
351         XMLNodeIterator i = _children.begin();
352         XMLNodeIterator tmp;
353         
354         while (i != _children.end()) {
355                 tmp = i;
356                 ++tmp;
357                 if ((*i)->name() == n) {
358                         _children.erase (i);
359                 }
360                 i = tmp;
361         }
362 }
363
364 void 
365 XMLNode::remove_nodes_and_delete(const string & n)
366 {
367         XMLNodeIterator i = _children.begin();
368         XMLNodeIterator tmp;
369         
370         while (i != _children.end()) {
371                 tmp = i;
372                 ++tmp;
373                 if ((*i)->name() == n) {
374                         delete *i;
375                         _children.erase (i);
376                 }
377                 i = tmp;
378         }
379 }
380
381 XMLProperty::XMLProperty(const string &n, const string &v)
382         : _name(n), 
383         _value(v) 
384
385 }
386
387 XMLProperty::~XMLProperty()
388 {
389 }
390
391 static XMLNode *
392 readnode(xmlNodePtr node)
393 {
394         string name, content;
395         xmlNodePtr child;
396         XMLNode *tmp;
397         xmlAttrPtr attr;
398         
399         if (node->name) {
400                 name = (char *) node->name;
401         }
402         
403         tmp = new XMLNode(name);
404         
405         for (attr = node->properties; attr; attr = attr->next) {
406                 content = "";
407                 if (attr->children) {
408                         content = (char *) attr->children->content;
409                 }
410                 tmp->add_property((char *) attr->name, content);
411         }
412         
413         if (node->content) {
414                 tmp->set_content((char *) node->content);
415         } else {
416                 tmp->set_content(string());
417         }
418         
419         for (child = node->children; child; child = child->next) {
420                 tmp->add_child_nocopy (*readnode(child));
421         }
422         
423         return tmp;
424 }
425
426 static void 
427 writenode(xmlDocPtr doc, XMLNode * n, xmlNodePtr p, int root = 0)
428 {
429         XMLPropertyList props;
430         XMLPropertyIterator curprop;
431         XMLNodeList children;
432         XMLNodeIterator curchild;
433         xmlNodePtr node;
434         
435         if (root) {
436                 node = doc->children = xmlNewDocNode(doc, 0, (xmlChar *) n->name().c_str(), 0);
437         } else {
438                 node = xmlNewChild(p, 0, (xmlChar *) n->name().c_str(), 0);
439         }
440             
441         if (n->is_content()) {
442                 node->type = XML_TEXT_NODE;
443                 xmlNodeSetContentLen(node, (const xmlChar *) n->content().c_str(), n->content().length());
444         }
445         
446         props = n->properties();
447         for (curprop = props.begin(); curprop != props.end(); ++curprop) {
448                 xmlSetProp(node, (xmlChar *) (*curprop)->name().c_str(), (xmlChar *) (*curprop)->value().c_str());
449         }
450             
451         children = n->children();
452         for (curchild = children.begin(); curchild != children.end(); ++curchild) {
453                 writenode(doc, *curchild, node);
454         }
455 }