root/trunk/libffado/src/libutil/serialize_expat_xml.cpp

Revision 2803, 9.3 kB (checked in by jwoithe, 3 years ago)

Cosmetic: capitalise "L" in "Linux".

"Linux" is a proper noun so it should start with a capital letter. These
changes are almost all within comments.

This patch was originally proposed by pander on the ffado-devel mailing
list. It has been expanded to cover all similar cases to maintain
consistency throughout the source tree.

Line 
1 /*
2  * Parts Copyright (C) 2005-2008 by Pieter Palmers
3  *
4  * This file is part of FFADO
5  * FFADO = Free FireWire (pro-)audio drivers for Linux
6  *
7  * FFADO is based upon FreeBoB.
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 2 of the License, or
12  * (at your option) version 3 of the License.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 /*
25  *
26  *  D-Bus++ - C++ bindings for D-Bus
27  *
28  *  Copyright (C) 2005-2007  Paolo Durante <shackan@gmail.com>
29  *
30  *
31  *  This library is free software; you can redistribute it and/or
32  *  modify it under the terms of the GNU Lesser General Public
33  *  License as published by the Free Software Foundation; either
34  *  version 2.1 of the License, or (at your option) any later version.
35  *
36  *  This library is distributed in the hope that it will be useful,
37  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
38  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
39  *  Lesser General Public License for more details.
40  *
41  *  You should have received a copy of the GNU Lesser General Public
42  *  License along with this library; if not, write to the Free Software
43  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
44  *
45  */
46
47
48 #include "serialize_expat_xml.h"
49 #include <expat.h>
50
51 #include <iostream>
52 #include <fstream>
53
54 IMPL_DEBUG_MODULE( Util::Xml::Node, Node, DEBUG_LEVEL_NORMAL );
55 IMPL_DEBUG_MODULE( Util::Xml::Document, Document, DEBUG_LEVEL_NORMAL );
56
57 std::istream& operator >> ( std::istream& in, Util::Xml::Document& doc )
58 {
59     std::stringbuf xmlbuf;
60     in.get(xmlbuf, '\0');
61     doc.from_xml(xmlbuf.str());
62
63     return in;
64 }
65
66 std::ostream& operator << ( std::ostream& out, const Util::Xml::Document& doc )
67 {
68     return out << doc.to_xml();
69 }
70
71 using namespace Util;
72 using namespace Util::Xml;
73
74 Error::Error( const char* error, int line, int column )
75 {
76     std::ostringstream estream;
77
78     estream << "line " << line << ", column " << column << ": " << error;
79
80     _error = estream.str();
81 }
82
83 Node::Node( const char* n, const char** a )
84 : name(n)
85 {
86     if(a)
87     for(int i = 0; a[i]; i += 2)
88     {
89         _attrs[a[i]] = a[i+1];
90
91         debugOutput(DEBUG_LEVEL_VERBOSE, "xml:\t%s = %s", a[i], a[i+1]);
92     }
93 }
94
95 Nodes Nodes::operator[]( const std::string& key )
96 {
97     Nodes result;
98
99     for(iterator i = begin(); i != end(); ++i)
100     {
101         Nodes part = (**i)[key];
102
103         result.insert(result.end(), part.begin(), part.end());
104     }
105     return result;
106 }
107
108 Nodes Nodes::select( const std::string& attr, const std::string& value )
109 {
110     Nodes result;
111
112     for(iterator i = begin(); i != end(); ++i)
113     {
114         if((*i)->get(attr) == value)
115             result.insert(result.end(), *i);
116     }
117     return result;
118 }
119
120 Nodes Node::operator[]( const std::string& key )
121 {
122     Nodes result;
123
124     if(key.length() == 0) return result;
125
126     for(Children::iterator i = children.begin(); i != children.end(); ++i)
127     {
128         if(i->name == key)
129             result.push_back(&(*i));
130     }
131     return result;
132 }
133
134 Nodes Node::find(const std::string &path)
135 {
136     std::string::size_type slash_pos = path.find_first_of( "/" );
137     if(slash_pos == std::string::npos) {
138         // end of the line
139         return (*this)[path];
140     } else {
141         // grab the prefix and suffix
142         std::string prefix = path.substr(0, slash_pos);
143         std::string suffix = path.substr(slash_pos+1);
144         // accumulate results over all nodes
145         Nodes results;
146         Nodes nodes = (*this)[prefix];
147         for(int i=0; i<nodes.size(); i++) {
148             Nodes tmp = nodes.at(i)->find(suffix);
149             for(int j=0; j<tmp.size(); j++) {
150                 results.push_back(tmp.at(j));
151             }
152         }
153         return results;
154     }
155 }
156
157 std::string Node::get( const std::string& attribute )
158 {
159     if(_attrs.find(attribute) != _attrs.end())
160         return _attrs[attribute];
161     else
162         return "";
163 }
164
165 void Node::set( const std::string& attribute, std::string value )
166 {
167     if(value.length())
168         _attrs[attribute] = value;
169     else
170         _attrs.erase(value);
171 }
172
173 std::string Node::to_xml() const
174 {
175     std::string xml;
176     int depth = 0;
177
178     _raw_xml(xml, depth);
179
180     return xml;
181 }
182
183 void Node::_raw_xml( std::string& xml, int& depth ) const
184 {
185     xml.append(depth*2, ' ');
186     xml.append("<"+name);
187
188     for(Attributes::const_iterator i = _attrs.begin(); i != _attrs.end(); ++i)
189     {
190         xml.append(" "+i->first+"=\""+i->second+"\"");
191     }
192
193     if(cdata.length() == 0 && children.size() == 0)
194     {
195         xml.append("/>\n");
196     }
197     else
198     {
199         xml.append(">");
200        
201         if(cdata.length())
202         {
203             xml.append(cdata);
204         }
205
206         if(children.size())
207         {
208             xml.append("\n");
209             depth++;
210
211             for(Children::const_iterator i = children.begin(); i != children.end(); ++i)
212             {
213                 i->_raw_xml(xml, depth);
214             }
215
216             depth--;
217             xml.append(depth*2, ' ');
218         }
219         xml.append("</"+name+">\n");
220     }
221 }
222
223 Document::Document()
224 : root(0), _depth(0)
225 {
226 }
227    
228 Document::Document( const std::string& xml )
229 : root(0), _depth(0)
230 {
231     from_xml(xml);
232 }
233
234 Document::~Document()
235 {
236     delete root;
237 }
238
239 struct Document::Expat
240 {
241     static void start_doctype_decl_handler(
242         void* data, const XML_Char* name, const XML_Char* sysid, const XML_Char* pubid, int has_internal_subset
243     );
244     static void end_doctype_decl_handler( void* data );
245     static void start_element_handler( void *data, const XML_Char *name, const XML_Char **atts );
246     static void character_data_handler( void *data, const XML_Char* chars, int len );
247     static void end_element_handler( void *data, const XML_Char *name );
248 };
249
250 void Document::from_xml( const std::string& xml )
251 {
252     _depth = 0;
253     delete root;
254     root = 0;
255
256     XML_Parser parser = XML_ParserCreate("UTF-8");
257
258     XML_SetUserData(parser, this);
259
260     XML_SetDoctypeDeclHandler(
261         parser,
262         Document::Expat::start_doctype_decl_handler,
263         Document::Expat::end_doctype_decl_handler
264     );
265
266     XML_SetElementHandler(
267         parser,
268         Document::Expat::start_element_handler,
269         Document::Expat::end_element_handler
270     );
271
272     XML_SetCharacterDataHandler(
273         parser,
274         Document::Expat::character_data_handler
275     );
276
277     XML_Status status = XML_Parse(parser, xml.c_str(), xml.length(), true);
278
279     if(status == XML_STATUS_ERROR)
280     {
281         const char* error = XML_ErrorString(XML_GetErrorCode(parser));
282         int line = XML_GetCurrentLineNumber(parser);
283         int column = XML_GetCurrentColumnNumber(parser);
284
285         XML_ParserFree(parser);
286
287         throw Error(error, line, column);
288     }
289     else
290     {
291         XML_ParserFree(parser);
292     }
293 }
294
295 std::string Document::to_xml() const
296 {
297     return root->to_xml();
298 }
299
300 void Document::Expat::start_doctype_decl_handler(
301     void* data, const XML_Char* name, const XML_Char* sysid, const XML_Char* pubid, int has_internal_subset
302 )
303 {
304 }
305
306 void Document::Expat::end_doctype_decl_handler( void* data )
307 {
308 }
309
310 void Document::Expat::start_element_handler( void *data, const XML_Char *name, const XML_Char **atts )
311 {
312     Document* doc = (Document*)data;
313
314     debugOutput(DEBUG_LEVEL_VERBOSE, "xml:%d -> %s", doc->_depth, name);
315
316     if(!doc->root)
317     {
318         doc->root = new Node(name, atts);
319     }
320     else
321     {
322         Node::Children* cld = &(doc->root->children);
323
324         for(int i = 1; i < doc->_depth; ++i)
325         {
326             cld = &(cld->back().children);
327         }
328         cld->push_back(Node(name, atts));
329
330         //std::cerr << doc->to_xml() << std::endl;
331     }
332     doc->_depth++;
333 }
334
335 void Document::Expat::character_data_handler( void *data, const XML_Char* chars, int len )
336 {
337     Document* doc = (Document*)data;
338
339     Node* nod = doc->root;
340
341     for(int i = 1; i < doc->_depth; ++i)
342     {
343         nod = &(nod->children.back());
344     }
345     int x, y;
346
347     x = 0;
348     y = len-1;
349
350     while(isspace(chars[y]) && y > 0) --y;
351     while(isspace(chars[x]) && x < y) ++x;
352
353     nod->cdata = std::string(chars, x, y+1);
354 }
355
356 void Document::Expat::end_element_handler( void *data, const char *name )
357 {
358     Document* doc = (Document*)data;
359
360     debugOutput(DEBUG_LEVEL_VERBOSE, "xml:%d <- %s", doc->_depth, name);
361
362     doc->_depth--;
363 }
364
365 void Document::create_root_node( const XML_Char *name )
366 {
367     if(!root)
368     {
369         delete root;
370         _depth = 0;
371     }
372     root = new Node(name, NULL);
373     _depth++;
374 }
375
376 void Document::write_to_file_formatted( const std::string filename )
377 {
378     std::string xml = to_xml();
379     std::ofstream file;
380     file.open(filename.c_str());
381     file << xml;
382     file.close();
383 }
384
385 void Document::load_from_file( const std::string filename )
386 {
387     std::string xml = "";
388     std::string chunk = "";
389
390     std::ifstream file;
391     if (!file) {
392         debugError("file not opened\n");
393         return;
394     }
395     file.open(filename.c_str());
396     while (file >> chunk) {
397         xml = xml + chunk;
398     }
399     file.close();
400     from_xml(xml);
401 }
Note: See TracBrowser for help on using the browser.