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