1
// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
3
* Copyright (C) 2010 Canonical Ltd
5
* This program is free software: you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License version 3 as
7
* published by the Free Software Foundation.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17
* Authored by: Thomi Richards <thomi.richards@canonical.com>
21
#include <boost/algorithm/string.hpp>
22
#include <boost/algorithm/string/split.hpp>
23
#include <boost/algorithm/string/classification.hpp>
24
#include <boost/bind.hpp>
25
#include <NuxCore/Logger.h>
26
#include "XPathQueryPart.h"
27
#include "Introspectable.h"
36
nux::logging::Logger logger("unity.debug.DebugDBusInterface");
39
// Stores a part of an XPath query.
40
XPathQueryPart::XPathQueryPart(std::string const& query_part)
42
std::vector<std::string> part_pieces;
43
boost::algorithm::split(part_pieces, query_part, boost::algorithm::is_any_of("[]="));
44
// Boost's split() implementation does not match it's documentation! According to the
45
// docs, it's not supposed to add empty strings, but it does, which is a PITA. This
46
// next line removes them:
47
part_pieces.erase( std::remove_if( part_pieces.begin(),
49
boost::bind( &std::string::empty, _1 ) ),
51
if (part_pieces.size() == 1)
53
node_name_ = part_pieces.at(0);
55
else if (part_pieces.size() == 3)
57
node_name_ = part_pieces.at(0);
58
param_name_ = part_pieces.at(1);
59
param_value_ = part_pieces.at(2);
63
LOG_WARNING(logger) << "Malformed query part: " << query_part;
64
// assume it's just a node name:
65
node_name_ = query_part;
69
bool XPathQueryPart::Matches(Introspectable* node) const
72
if (param_name_ == "")
74
matches = node->GetName() == node_name_;
78
GVariantBuilder child_builder;
79
g_variant_builder_init(&child_builder, G_VARIANT_TYPE("a{sv}"));
80
node->AddProperties(&child_builder);
81
GVariant* prop_dict = g_variant_builder_end(&child_builder);
82
GVariant *prop_value = g_variant_lookup_value(prop_dict, param_name_.c_str(), NULL);
84
if (prop_value != NULL)
86
GVariantClass prop_val_type = g_variant_classify(prop_value);
87
// it'd be nice to be able to do all this with one method. However, the booleans need
88
// special treatment, and I can't figure out how to group all the integer types together
89
// without resorting to template functions.... and we all know what happens when you
90
// start doing that...
91
switch (prop_val_type)
93
case G_VARIANT_CLASS_STRING:
95
const gchar* prop_val = g_variant_get_string(prop_value, NULL);
96
if (g_strcmp0(prop_val, param_value_.c_str()) == 0)
102
case G_VARIANT_CLASS_BOOLEAN:
104
std::string value = boost::to_upper_copy(param_value_);
105
bool p = value == "TRUE" ||
109
matches = (g_variant_get_boolean(prop_value) == p);
112
case G_VARIANT_CLASS_BYTE:
114
// It would be nice if I could do all the integer types together, but I couldn't see how...
115
std::stringstream stream(param_value_);
116
int val; // changing this to guchar causes problems.
118
matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
119
val == g_variant_get_byte(prop_value);
122
case G_VARIANT_CLASS_INT16:
124
std::stringstream stream(param_value_);
127
matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
128
val == g_variant_get_int16(prop_value);
131
case G_VARIANT_CLASS_UINT16:
133
std::stringstream stream(param_value_);
136
matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
137
val == g_variant_get_uint16(prop_value);
140
case G_VARIANT_CLASS_INT32:
142
std::stringstream stream(param_value_);
145
matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
146
val == g_variant_get_int32(prop_value);
149
case G_VARIANT_CLASS_UINT32:
151
std::stringstream stream(param_value_);
154
matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
155
val == g_variant_get_uint32(prop_value);
158
case G_VARIANT_CLASS_INT64:
160
std::stringstream stream(param_value_);
163
matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
164
val == g_variant_get_int64(prop_value);
167
case G_VARIANT_CLASS_UINT64:
169
std::stringstream stream(param_value_);
172
matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
173
val == g_variant_get_uint64(prop_value);
177
LOG_WARNING(logger) << "Unable to match against property of unknown type.";
180
g_variant_unref(prop_value);
181
g_variant_unref(prop_dict);