blob: d3cc3ab82317149510892f57252ab84c2da7979a [file] [log] [blame]
Emeric Vigier2f625822012-08-06 11:09:52 -04001/*
2 *
3 * D-Bus++ - C++ bindings for D-Bus
4 *
5 * Copyright (C) 2005-2007 Paolo Durante <shackan@gmail.com>
6 *
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24
25#include "xml.h"
26
27#include <expat.h>
28
29std::istream &operator >> (std::istream &in, DBus::Xml::Document &doc)
30{
31 std::stringbuf xmlbuf;
32 in.get(xmlbuf, '\0');
33 doc.from_xml(xmlbuf.str());
34
35 return in;
36}
37
38std::ostream &operator << (std::ostream &out, const DBus::Xml::Document &doc)
39{
40 return out << doc.to_xml();
41}
42
43using namespace DBus;
44using namespace DBus::Xml;
45
46Error::Error(const char *error, int line, int column)
47{
48 std::ostringstream estream;
49
50 estream << "line " << line << ", column " << column << ": " << error;
51
52 _error = estream.str();
53}
54
55Node::Node(const char *n, const char **a)
56 : name(n)
57{
58 if (a)
59 for (int i = 0; a[i]; i += 2)
60 {
61 _attrs[a[i]] = a[i + 1];
62
63 //debug_log("xml:\t%s = %s", a[i], a[i+1]);
64 }
65}
66
67Nodes Nodes::operator[](const std::string &key)
68{
69 Nodes result;
70
71 for (iterator i = begin(); i != end(); ++i)
72 {
73 Nodes part = (**i)[key];
74
75 result.insert(result.end(), part.begin(), part.end());
76 }
77 return result;
78}
79
80Nodes Nodes::select(const std::string &attr, const std::string &value)
81{
82 Nodes result;
83
84 for (iterator i = begin(); i != end(); ++i)
85 {
86 if ((*i)->get(attr) == value)
87 result.insert(result.end(), *i);
88 }
89 return result;
90}
91
92Nodes Node::operator[](const std::string &key)
93{
94 Nodes result;
95
96 if (key.length() == 0) return result;
97
98 for (Children::iterator i = children.begin(); i != children.end(); ++i)
99 {
100 if (i->name == key)
101 result.push_back(&(*i));
102 }
103 return result;
104}
105
106std::string Node::get(const std::string &attribute)
107{
108 if (_attrs.find(attribute) != _attrs.end())
109 return _attrs[attribute];
110 else
111 return "";
112}
113
114void Node::set(const std::string &attribute, std::string value)
115{
116 if (value.length())
117 _attrs[attribute] = value;
118 else
119 _attrs.erase(value);
120}
121
122std::string Node::to_xml() const
123{
124 std::string xml;
125 int depth = 0;
126
127 _raw_xml(xml, depth);
128
129 return xml;
130}
131
132void Node::_raw_xml(std::string &xml, int &depth) const
133{
134 xml.append(depth * 2, ' ');
135 xml.append("<" + name);
136
137 for (Attributes::const_iterator i = _attrs.begin(); i != _attrs.end(); ++i)
138 {
139 xml.append(" " + i->first + "=\"" + i->second + "\"");
140 }
141
142 if (cdata.length() == 0 && children.size() == 0)
143 {
144 xml.append("/>\n");
145 }
146 else
147 {
148 xml.append(">");
149
150 if (cdata.length())
151 {
152 xml.append(cdata);
153 }
154
155 if (children.size())
156 {
157 xml.append("\n");
158 depth++;
159
160 for (Children::const_iterator i = children.begin(); i != children.end(); ++i)
161 {
162 i->_raw_xml(xml, depth);
163 }
164
165 depth--;
166 xml.append(depth * 2, ' ');
167 }
168 xml.append("</" + name + ">\n");
169 }
170}
171
172Document::Document()
173 : root(0), _depth(0)
174{
175}
176
177Document::Document(const std::string &xml)
178 : root(0), _depth(0)
179{
180 from_xml(xml);
181}
182
183Document::~Document()
184{
185 delete root;
186}
187
188struct Document::Expat
189{
190 static void start_doctype_decl_handler(
191 void *data, const XML_Char *name, const XML_Char *sysid, const XML_Char *pubid, int has_internal_subset
192 );
193 static void end_doctype_decl_handler(void *data);
194 static void start_element_handler(void *data, const XML_Char *name, const XML_Char **atts);
195 static void character_data_handler(void *data, const XML_Char *chars, int len);
196 static void end_element_handler(void *data, const XML_Char *name);
197};
198
199void Document::from_xml(const std::string &xml)
200{
201 _depth = 0;
202 delete root;
203 root = 0;
204
205 XML_Parser parser = XML_ParserCreate("UTF-8");
206
207 XML_SetUserData(parser, this);
208
209 XML_SetDoctypeDeclHandler(
210 parser,
211 Document::Expat::start_doctype_decl_handler,
212 Document::Expat::end_doctype_decl_handler
213 );
214
215 XML_SetElementHandler(
216 parser,
217 Document::Expat::start_element_handler,
218 Document::Expat::end_element_handler
219 );
220
221 XML_SetCharacterDataHandler(
222 parser,
223 Document::Expat::character_data_handler
224 );
225
226 XML_Status status = XML_Parse(parser, xml.c_str(), xml.length(), true);
227
228 if (status == XML_STATUS_ERROR)
229 {
230 const char *error = XML_ErrorString(XML_GetErrorCode(parser));
231 int line = XML_GetCurrentLineNumber(parser);
232 int column = XML_GetCurrentColumnNumber(parser);
233
234 XML_ParserFree(parser);
235
236 throw Error(error, line, column);
237 }
238 else
239 {
240 XML_ParserFree(parser);
241 }
242}
243
244std::string Document::to_xml() const
245{
246 return root->to_xml();
247}
248
249void Document::Expat::start_doctype_decl_handler(
250 void *data, const XML_Char *name, const XML_Char *sysid, const XML_Char *pubid, int has_internal_subset
251)
252{
253}
254
255void Document::Expat::end_doctype_decl_handler(void *data)
256{
257}
258
259void Document::Expat::start_element_handler(void *data, const XML_Char *name, const XML_Char **atts)
260{
261 Document *doc = (Document *)data;
262
263 //debug_log("xml:%d -> %s", doc->_depth, name);
264
265 if (!doc->root)
266 {
267 doc->root = new Node(name, atts);
268 }
269 else
270 {
271 Node::Children *cld = &(doc->root->children);
272
273 for (int i = 1; i < doc->_depth; ++i)
274 {
275 cld = &(cld->back().children);
276 }
277 cld->push_back(Node(name, atts));
278
279 //std::cerr << doc->to_xml() << std::endl;
280 }
281 doc->_depth++;
282}
283
284void Document::Expat::character_data_handler(void *data, const XML_Char *chars, int len)
285{
286 Document *doc = (Document *)data;
287
288 Node *nod = doc->root;
289
290 for (int i = 1; i < doc->_depth; ++i)
291 {
292 nod = &(nod->children.back());
293 }
294 int x, y;
295
296 x = 0;
297 y = len - 1;
298
299 while (isspace(chars[y]) && y > 0) --y;
300 while (isspace(chars[x]) && x < y) ++x;
301
302 nod->cdata = std::string(chars, x, y + 1);
303}
304
305void Document::Expat::end_element_handler(void *data, const XML_Char *name)
306{
307 Document *doc = (Document *)data;
308
309 //debug_log("xml:%d <- %s", doc->_depth, name);
310
311 doc->_depth--;
312}
313