03fa11627976ca6bff3fa26ad1fcec849acaf8b6
[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 = xmlSaveFormatFile(_filename.c_str(), doc, 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 const XMLNodeList & 
220 XMLNode::children(const string & n) const
221 {
222         static XMLNodeList retval;
223         XMLNodeConstIterator cur;
224         
225         if (n.length() == 0) {
226                 return _children;
227         }
228             
229         retval.erase(retval.begin(), retval.end());
230         
231         for (cur = _children.begin(); cur != _children.end(); ++cur) {
232                 if ((*cur)->name() == n) {
233                         retval.insert(retval.end(), *cur);
234                 }
235         }
236             
237         return retval;
238 }
239
240 XMLNode *
241 XMLNode::add_child(const char * n)
242 {
243         return add_child_copy(XMLNode (n));
244 }
245
246 void
247 XMLNode::add_child_nocopy (XMLNode& n)
248 {
249         _children.insert(_children.end(), &n);
250 }
251
252 XMLNode *
253 XMLNode::add_child_copy(const XMLNode& n)
254 {
255         XMLNode *copy = new XMLNode (n);
256         _children.insert(_children.end(), copy);
257         return copy;
258 }
259
260 XMLNode *
261 XMLNode::add_content(const string & c)
262 {
263         return add_child_copy(XMLNode (string(), c));
264 }
265
266 XMLProperty *
267 XMLNode::property(const char * n)
268 {
269         string ns(n);
270         if (_propmap.find(ns) == _propmap.end()) {
271                 return 0;
272         }
273         
274         return _propmap[ns];
275 }
276
277 XMLProperty *
278 XMLNode::add_property(const char * n, const string & v)
279 {
280         string ns(n);
281         if(_propmap.find(ns) != _propmap.end()){
282                 remove_property(ns);
283         }
284
285         XMLProperty *tmp = new XMLProperty(ns, v);
286
287         if (!tmp) {
288                 return 0;
289         }
290
291         _propmap[tmp->name()] = tmp;
292         _proplist.insert(_proplist.end(), tmp);
293
294         return tmp;
295 }
296
297 XMLProperty *
298 XMLNode::add_property(const char * n, const char * v)
299 {
300         string vs(v);
301         return add_property(n, vs);
302 }
303
304 void 
305 XMLNode::remove_property(const string & n)
306 {
307         if (_propmap.find(n) != _propmap.end()) {
308                 _proplist.remove(_propmap[n]);
309                 _propmap.erase(n);
310         }
311 }
312
313 void 
314 XMLNode::remove_nodes(const string & n)
315 {
316         XMLNodeIterator i = _children.begin();
317         XMLNodeIterator tmp;
318         
319         while (i != _children.end()) {
320                 tmp = i;
321                 ++tmp;
322                 if ((*i)->name() == n) {
323                         _children.erase (i);
324                 }
325                 i = tmp;
326         }
327 }
328
329 void 
330 XMLNode::remove_nodes_and_delete(const string & n)
331 {
332         XMLNodeIterator i = _children.begin();
333         XMLNodeIterator tmp;
334         
335         while (i != _children.end()) {
336                 tmp = i;
337                 ++tmp;
338                 if ((*i)->name() == n) {
339                         delete *i;
340                         _children.erase (i);
341                 }
342                 i = tmp;
343         }
344 }
345
346 XMLProperty::XMLProperty(const string &n, const string &v)
347         : _name(n), 
348         _value(v) 
349
350 }
351
352 XMLProperty::~XMLProperty()
353 {
354 }
355
356 static XMLNode *
357 readnode(xmlNodePtr node)
358 {
359         string name, content;
360         xmlNodePtr child;
361         XMLNode *tmp;
362         xmlAttrPtr attr;
363         
364         if (node->name) {
365                 name = (char *) node->name;
366         }
367         
368         tmp = new XMLNode(name);
369         
370         for (attr = node->properties; attr; attr = attr->next) {
371                 content = "";
372                 if (attr->children) {
373                         content = (char *) attr->children->content;
374                 }
375                 tmp->add_property((char *) attr->name, content);
376         }
377         
378         if (node->content) {
379                 tmp->set_content((char *) node->content);
380         } else {
381                 tmp->set_content(string());
382         }
383         
384         for (child = node->children; child; child = child->next) {
385                 tmp->add_child_nocopy (*readnode(child));
386         }
387         
388         return tmp;
389 }
390
391 static void 
392 writenode(xmlDocPtr doc, XMLNode * n, xmlNodePtr p, int root = 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 = xmlNewDocNode(doc, 0, (xmlChar *) n->name().c_str(), 0);
402         } else {
403                 node = xmlNewChild(p, 0, (xmlChar *) n->name().c_str(), 0);
404         }
405             
406         if (n->is_content()) {
407                 node->type = XML_TEXT_NODE;
408                 xmlNodeSetContentLen(node, (const xmlChar *) n->content().c_str(), n->content().length());
409         }
410         
411         props = n->properties();
412         for (curprop = props.begin(); curprop != props.end(); ++curprop) {
413                 xmlSetProp(node, (xmlChar *) (*curprop)->name().c_str(), (xmlChar *) (*curprop)->value().c_str());
414         }
415             
416         children = n->children();
417         for (curchild = children.begin(); curchild != children.end(); ++curchild) {
418                 writenode(doc, *curchild, node);
419         }
420 }