2
* Copyright © 2012 Canonical Ltd.
4
* This program is free software: you can redistribute it and/or modify it
5
* under the terms of the GNU Lesser General Public License version 3,
6
* as published by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU Lesser General Public License for more details.
13
* You should have received a copy of the GNU Lesser General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16
* Authored by: Thomas Voß <thomas.voss@canonical.com>
19
#include <core/dbus/introspection_parser.h>
21
#include <libxml/xmlreader.h>
32
std::string safe_string_construct(const char* c)
34
return std::move(std::string((c ? c : "")));
37
struct IntrospectionParser::Private
39
std::function<void(const Node&)> on_node;
40
std::function<void()> on_node_done;
41
std::function<void(const Interface&)> on_interface;
42
std::function<void()> on_interface_done;
43
std::function<void(const Method&)> on_method;
44
std::function<void()> on_method_done;
45
std::function<void(const Property&)> on_property;
46
std::function<void(const Signal&)> on_signal;
47
std::function<void()> on_signal_done;
48
std::function<void(const Argument&)> on_argument;
49
std::function<void()> on_argument_done;
50
std::function<void(const Annotation&)> on_annotation;
51
std::function<void()> on_annotation_done;
55
IntrospectionParser::IntrospectionParser() : d(new Private())
59
IntrospectionParser::~IntrospectionParser()
63
#define NAMED_ENUMERATION_ELEMENT(element) {element, #element}
65
bool IntrospectionParser::invoke_for(const std::string& filename)
67
static const char* empty_encoding = nullptr;
68
// We consciously do not check the dtd here
69
static const int parser_options = 0;
71
auto reader = std::shared_ptr<xmlTextReader>(
72
xmlReaderForFile(filename.c_str(),
75
[](xmlTextReaderPtr reader)
77
if (reader == nullptr)
80
xmlFreeTextReader(reader);
86
const std::map<std::string, std::function<void()>> vtable_done =
88
{Node::element_name(), d->on_node_done},
89
{Interface::element_name(), d->on_interface_done},
90
{Method::element_name(), d->on_method_done},
91
{Argument::element_name(), d->on_argument_done},
92
{Annotation::element_name(), d->on_annotation_done},
93
{Signal::element_name(), d->on_signal_done}
96
const std::map<std::string, std::function<void(xmlTextReaderPtr)>> vtable =
99
Annotation::element_name(),
100
[this](xmlTextReaderPtr reader)
102
if (!d->on_annotation)
107
safe_string_construct(reinterpret_cast<const char*>(xmlTextReaderGetAttribute(reader, BAD_CAST Annotation::name_attribute_name()))),
108
safe_string_construct(reinterpret_cast<const char*>(xmlTextReaderGetAttribute(reader, BAD_CAST Annotation::value_attribute_name())))});
112
Node::element_name(),
113
[this](xmlTextReaderPtr reader)
118
auto attribute_name = reinterpret_cast<const char*>(
119
xmlTextReaderGetAttribute(reader,
120
BAD_CAST Node::name_attribute_name()));
122
d->on_node(Node{safe_string_construct(attribute_name)});
126
Interface::element_name(),
127
[this](xmlTextReaderPtr reader)
129
if (!d->on_interface)
134
safe_string_construct(reinterpret_cast<const char*>(
135
xmlTextReaderGetAttribute(
137
BAD_CAST Interface::name_attribute_name())))});
141
Argument::element_name(),
142
[this](xmlTextReaderPtr reader)
147
static const std::map<std::string, Argument::Direction> direction_lut =
149
{"", Argument::Direction::context},
150
{"in", Argument::Direction::in},
151
{"out", Argument::Direction::out}
154
auto name_attribute = reinterpret_cast<const char*>(
155
xmlTextReaderGetAttribute(
157
BAD_CAST Argument::name_attribute_name()));
159
Argument::Direction dir = Argument::Direction::context;
162
dir = direction_lut.at(
163
safe_string_construct(reinterpret_cast<const char*>(
164
xmlTextReaderGetAttribute(
166
BAD_CAST Argument::direction_attribute_name()))));
167
} catch(const std::out_of_range& e)
169
throw std::runtime_error(
170
std::string("Could not interpret direction for argument with name: ") +
171
safe_string_construct(name_attribute));
176
safe_string_construct(name_attribute),
177
safe_string_construct(reinterpret_cast<const char*>(
178
xmlTextReaderGetAttribute(
180
BAD_CAST Argument::type_attribute_name()))),
185
Method::element_name(),
186
[this](xmlTextReaderPtr reader)
193
safe_string_construct(
194
reinterpret_cast<const char*>(
195
xmlTextReaderGetAttribute(
197
BAD_CAST Method::name_attribute_name())))});
201
Signal::element_name(),
202
[this](xmlTextReaderPtr reader)
209
safe_string_construct(
210
reinterpret_cast<const char*>(
211
xmlTextReaderGetAttribute(
213
BAD_CAST Signal::name_attribute_name())))});
217
Property::element_name(),
218
[this](xmlTextReaderPtr reader)
223
static const std::map<std::string, Property::Access> access_lut =
225
{"read", Property::Access::read},
226
{"write", Property::Access::write},
227
{"readwrite", Property::Access::read_write}
230
auto property_name = reinterpret_cast<const char*>(
231
xmlTextReaderGetAttribute(
233
BAD_CAST Property::name_attribute_name()));
239
safe_string_construct(reinterpret_cast<const char*>(
240
xmlTextReaderGetAttribute(
242
BAD_CAST Property::access_attribute_name()))));
243
} catch(const std::out_of_range& e)
245
throw std::runtime_error(
246
std::string("Could not determine read/write setup of property ") + property_name);
251
safe_string_construct(property_name),
252
safe_string_construct(reinterpret_cast<const char*>(
253
xmlTextReaderGetAttribute(
255
BAD_CAST Property::type_attribute_name()))),
261
enum class NodeType : int
267
document_fragment = 11,
273
entity_reference = 5,
276
processing_instruction = 7,
277
significant_whitespace = 14,
283
static std::map<NodeType, std::string> node_type_lut=
285
NAMED_ENUMERATION_ELEMENT(NodeType::attribute),
286
NAMED_ENUMERATION_ELEMENT(NodeType::cdata),
287
NAMED_ENUMERATION_ELEMENT(NodeType::comment),
288
NAMED_ENUMERATION_ELEMENT(NodeType::document),
289
NAMED_ENUMERATION_ELEMENT(NodeType::document_fragment),
290
NAMED_ENUMERATION_ELEMENT(NodeType::document_type),
291
NAMED_ENUMERATION_ELEMENT(NodeType::element),
292
NAMED_ENUMERATION_ELEMENT(NodeType::end_element),
293
NAMED_ENUMERATION_ELEMENT(NodeType::entity),
294
NAMED_ENUMERATION_ELEMENT(NodeType::end_entity),
295
NAMED_ENUMERATION_ELEMENT(NodeType::entity_reference),
296
NAMED_ENUMERATION_ELEMENT(NodeType::none),
297
NAMED_ENUMERATION_ELEMENT(NodeType::notation),
298
NAMED_ENUMERATION_ELEMENT(NodeType::processing_instruction),
299
NAMED_ENUMERATION_ELEMENT(NodeType::significant_whitespace),
300
NAMED_ENUMERATION_ELEMENT(NodeType::text),
301
NAMED_ENUMERATION_ELEMENT(NodeType::whitespace),
302
NAMED_ENUMERATION_ELEMENT(NodeType::xml_declaration)
305
enum class Status : int
312
int status = xmlTextReaderRead(reader.get());
314
if (Status::error == static_cast<Status>(status))
317
while (Status::has_more == static_cast<Status>(status))
319
auto node_name = reinterpret_cast<const char*>(
320
xmlTextReaderConstName(reader.get()));
321
switch(static_cast<NodeType>(xmlTextReaderNodeType(reader.get())))
323
case NodeType::element:
324
if (vtable.count(safe_string_construct(node_name)) > 0)
326
vtable.at(safe_string_construct(node_name))(reader.get());
329
if (xmlTextReaderIsEmptyElement(reader.get()))
331
if (vtable_done.count(safe_string_construct(node_name)) > 0)
333
vtable_done.at(safe_string_construct(node_name))();
337
case NodeType::end_element:
338
if (vtable_done.count(
339
safe_string_construct((const char*) xmlTextReaderConstName(reader.get()))) > 0)
341
vtable_done.at(safe_string_construct((const char*) xmlTextReaderConstName(reader.get())))();
347
status = xmlTextReaderRead(reader.get());
350
if (Status::error == static_cast<Status>(status))
353
return Status::done == static_cast<Status>(status);
356
void IntrospectionParser::on_node(const std::function<void(const Node&)>& f)
361
void IntrospectionParser::on_node_done(const std::function<void()>& f)
366
void IntrospectionParser::on_interface(const std::function<void(const Interface&)>& f)
371
void IntrospectionParser::on_interface_done(const std::function<void()>& f)
373
d->on_interface_done = f;
376
void IntrospectionParser::on_method(const std::function<void(const Method&)>& f)
381
void IntrospectionParser::on_method_done(const std::function<void()>& f)
383
d->on_method_done = f;
386
void IntrospectionParser::on_property(const std::function<void(const Property&)>& f)
391
void IntrospectionParser::on_signal(const std::function<void(const Signal&)>& f)
396
void IntrospectionParser::on_signal_done(const std::function<void()>& f)
398
d->on_signal_done = f;
401
void IntrospectionParser::on_argument(const std::function<void(const Argument&)>& f)
406
void IntrospectionParser::on_argument_done(const std::function<void()>& f)
408
d->on_argument_done = f;
411
void IntrospectionParser::on_annotation(const std::function<void(const Annotation&)>& f)
413
d->on_annotation = f;
416
void IntrospectionParser::on_annotation_done(const std::function<void()>& f)
418
d->on_annotation_done = f;