Back to index

unity  6.0.0
XPathQueryPart.cpp
Go to the documentation of this file.
00001 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
00002 /*
00003  * Copyright (C) 2010 Canonical Ltd
00004  *
00005  * This program is free software: you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 3 as
00007  * published by the Free Software Foundation.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016  *
00017  * Authored by: Thomi Richards <thomi.richards@canonical.com>
00018  */
00019 
00020 #include <sstream>
00021 #include <boost/algorithm/string.hpp>
00022 #include <boost/algorithm/string/split.hpp>
00023 #include <boost/algorithm/string/classification.hpp>
00024 #include <boost/bind.hpp>
00025 #include <NuxCore/Logger.h>
00026 #include "XPathQueryPart.h"
00027 #include "Introspectable.h"
00028 
00029 namespace unity
00030 {
00031 
00032 namespace debug
00033 {
00034 namespace
00035 {
00036   nux::logging::Logger logger("unity.debug.DebugDBusInterface");
00037 }
00038 
00039 // Stores a part of an XPath query.
00040 XPathQueryPart::XPathQueryPart(std::string const& query_part)
00041 {
00042   std::vector<std::string> part_pieces;
00043   boost::algorithm::split(part_pieces, query_part, boost::algorithm::is_any_of("[]="));
00044   // Boost's split() implementation does not match it's documentation! According to the
00045   // docs, it's not supposed to add empty strings, but it does, which is a PITA. This
00046   // next line removes them:
00047   part_pieces.erase( std::remove_if( part_pieces.begin(),
00048                                       part_pieces.end(),
00049                                       boost::bind( &std::string::empty, _1 ) ),
00050                     part_pieces.end());
00051   if (part_pieces.size() == 1)
00052   {
00053     node_name_ = part_pieces.at(0);
00054   }
00055   else if (part_pieces.size() == 3)
00056   {
00057     node_name_ = part_pieces.at(0);
00058     param_name_ = part_pieces.at(1);
00059     param_value_ = part_pieces.at(2);
00060   }
00061   else
00062   {
00063     LOG_WARNING(logger) << "Malformed query part: " << query_part;
00064     // assume it's just a node name:
00065     node_name_ = query_part;
00066   }
00067 }
00068 
00069 bool XPathQueryPart::Matches(Introspectable* node) const
00070 {
00071   bool matches = false;
00072   if (param_name_ == "")
00073   {
00074     matches = (node_name_ == "*" || node->GetName() == node_name_);
00075   }
00076   else
00077   {
00078     GVariantBuilder  child_builder;
00079     g_variant_builder_init(&child_builder, G_VARIANT_TYPE("a{sv}"));
00080     g_variant_builder_add(&child_builder, "{sv}", "id", g_variant_new_uint64(node->GetIntrospectionId()));
00081     node->AddProperties(&child_builder);
00082     GVariant* prop_dict = g_variant_builder_end(&child_builder);
00083     GVariant *prop_value = g_variant_lookup_value(prop_dict, param_name_.c_str(), NULL);
00084 
00085     if (prop_value != NULL)
00086     {
00087       GVariantClass prop_val_type = g_variant_classify(prop_value);
00088       // it'd be nice to be able to do all this with one method. However, the booleans need
00089       // special treatment, and I can't figure out how to group all the integer types together
00090       // without resorting to template functions.... and we all know what happens when you
00091       // start doing that...
00092       switch (prop_val_type)
00093       {
00094         case G_VARIANT_CLASS_STRING:
00095         {
00096           const gchar* prop_val = g_variant_get_string(prop_value, NULL);
00097           if (g_strcmp0(prop_val, param_value_.c_str()) == 0)
00098           {
00099             matches = true;
00100           }
00101         }
00102         break;
00103         case G_VARIANT_CLASS_BOOLEAN:
00104         {
00105           std::string value = boost::to_upper_copy(param_value_);
00106           bool p = value == "TRUE" ||
00107                     value == "ON" ||
00108                     value == "YES" ||
00109                     value == "1";
00110           matches = (g_variant_get_boolean(prop_value) == p);
00111         }
00112         break;
00113         case G_VARIANT_CLASS_BYTE:
00114         {
00115           // It would be nice if I could do all the integer types together, but I couldn't see how...
00116           std::stringstream stream(param_value_);
00117           int val; // changing this to guchar causes problems.
00118           stream >> val;
00119           matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
00120                     val == g_variant_get_byte(prop_value);
00121         }
00122         break;
00123         case G_VARIANT_CLASS_INT16:
00124         {
00125           std::stringstream stream(param_value_);
00126           gint16 val;
00127           stream >> val;
00128           matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
00129                     val == g_variant_get_int16(prop_value);
00130         }
00131         break;
00132         case G_VARIANT_CLASS_UINT16:
00133         {
00134           std::stringstream stream(param_value_);
00135           guint16 val;
00136           stream >> val;
00137           matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
00138                     val == g_variant_get_uint16(prop_value);
00139         }
00140         break;
00141         case G_VARIANT_CLASS_INT32:
00142         {
00143           std::stringstream stream(param_value_);
00144           gint32 val;
00145           stream >> val;
00146           matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
00147                     val == g_variant_get_int32(prop_value);
00148         }
00149         break;
00150         case G_VARIANT_CLASS_UINT32:
00151         {
00152           std::stringstream stream(param_value_);
00153           guint32 val;
00154           stream >> val;
00155           matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
00156                     val == g_variant_get_uint32(prop_value);
00157         }
00158         break;
00159         case G_VARIANT_CLASS_INT64:
00160         {
00161           std::stringstream stream(param_value_);
00162           gint64 val;
00163           stream >> val;
00164           matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
00165                     val == g_variant_get_int64(prop_value);
00166         }
00167         break;
00168         case G_VARIANT_CLASS_UINT64:
00169         {
00170           std::stringstream stream(param_value_);
00171           guint64 val;
00172           stream >> val;
00173           matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
00174                     val == g_variant_get_uint64(prop_value);
00175         }
00176         break;
00177       default:
00178         LOG_WARNING(logger) << "Unable to match against property of unknown type.";
00179       };
00180     }
00181     g_variant_unref(prop_value);
00182     g_variant_unref(prop_dict);
00183   }
00184 
00185   return matches;
00186 }
00187 
00188 }
00189 }