Home | History | Annotate | Download | only in chromeos-dbus-bindings
      1 // Copyright 2014 The Chromium OS Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chromeos-dbus-bindings/dbus_signature.h"
      6 
      7 #include <base/logging.h>
      8 #include <base/strings/stringprintf.h>
      9 #include <brillo/strings/string_utils.h>
     10 #include <dbus/dbus-protocol.h>
     11 
     12 using base::StringPrintf;
     13 using std::string;
     14 using std::vector;
     15 
     16 namespace chromeos_dbus_bindings {
     17 
     18 // static
     19 const char DbusSignature::kArrayTypename[] = "std::vector";
     20 const char DbusSignature::kBooleanTypename[] = "bool";
     21 const char DbusSignature::kByteTypename[] = "uint8_t";
     22 const char DbusSignature::kDefaultObjectPathTypename[] = "dbus::ObjectPath";
     23 const char DbusSignature::kDictTypename[] = "std::map";
     24 const char DbusSignature::kDoubleTypename[] = "double";
     25 const char DbusSignature::kSigned16Typename[] = "int16_t";
     26 const char DbusSignature::kSigned32Typename[] = "int32_t";
     27 const char DbusSignature::kSigned64Typename[] = "int64_t";
     28 const char DbusSignature::kStringTypename[] = "std::string";
     29 const char DbusSignature::kUnixFdTypename[] = "dbus::FileDescriptor";
     30 const char DbusSignature::kUnsigned16Typename[] = "uint16_t";
     31 const char DbusSignature::kUnsigned32Typename[] = "uint32_t";
     32 const char DbusSignature::kUnsigned64Typename[] = "uint64_t";
     33 const char DbusSignature::kVariantTypename[] = "brillo::Any";
     34 const char DbusSignature::kVariantDictTypename[] = "brillo::VariantDictionary";
     35 const char DbusSignature::kTupleTypename[] = "std::tuple";
     36 
     37 DbusSignature::DbusSignature()
     38     : object_path_typename_(kDefaultObjectPathTypename) {}
     39 
     40 bool DbusSignature::Parse(const string& signature, string* output) {
     41   string::const_iterator end;
     42   if (!GetTypenameForSignature(
     43           signature.begin(), signature.end(), &end, output)) {
     44     LOG(ERROR) << "Parse failed for signature " << signature;
     45     return false;
     46   }
     47   if (end != signature.end()) {
     48     LOG(WARNING) << "A portion of signature " << signature
     49                  << " is left unparsed: " << string(end, signature.end());
     50   }
     51   return true;
     52 }
     53 
     54 bool DbusSignature::GetTypenameForSignature(
     55     string::const_iterator signature,
     56     string::const_iterator end,
     57     string::const_iterator* next,
     58     string* output) {
     59   if (signature == end) {
     60     LOG(ERROR) << "Signature is empty";
     61     return false;
     62   }
     63 
     64   string::const_iterator cur = signature;
     65   int signature_value = *cur++;
     66   switch (signature_value) {
     67     case DBUS_STRUCT_BEGIN_CHAR:
     68       if (!GetStructTypenameForSignature(cur, end, &cur, output)) {
     69         return false;
     70       }
     71       break;
     72 
     73     case DBUS_TYPE_ARRAY:
     74       if (!GetArrayTypenameForSignature(cur, end, &cur, output)) {
     75         return false;
     76       }
     77       break;
     78 
     79     case DBUS_TYPE_BOOLEAN:
     80       *output = kBooleanTypename;
     81       break;
     82 
     83     case DBUS_TYPE_BYTE:
     84       *output = kByteTypename;
     85       break;
     86 
     87     case DBUS_TYPE_DOUBLE:
     88       *output = kDoubleTypename;
     89       break;
     90 
     91     case DBUS_TYPE_OBJECT_PATH:
     92       *output = object_path_typename_;
     93       break;
     94 
     95     case DBUS_TYPE_INT16:
     96       *output = kSigned16Typename;
     97       break;
     98 
     99     case DBUS_TYPE_INT32:
    100       *output = kSigned32Typename;
    101       break;
    102 
    103     case DBUS_TYPE_INT64:
    104       *output = kSigned64Typename;
    105       break;
    106 
    107     case DBUS_TYPE_STRING:
    108       *output = kStringTypename;
    109       break;
    110 
    111     case DBUS_TYPE_UNIX_FD:
    112       *output = kUnixFdTypename;
    113       break;
    114 
    115     case DBUS_TYPE_UINT16:
    116       *output = kUnsigned16Typename;
    117       break;
    118 
    119     case DBUS_TYPE_UINT32:
    120       *output = kUnsigned32Typename;
    121       break;
    122 
    123     case DBUS_TYPE_UINT64:
    124       *output = kUnsigned64Typename;
    125       break;
    126 
    127     case DBUS_TYPE_VARIANT:
    128       *output = kVariantTypename;
    129       break;
    130 
    131     default:
    132       LOG(ERROR) << "Unexpected token " << *signature;
    133       return false;
    134   }
    135 
    136   if (next) {
    137     *next = cur;
    138   }
    139 
    140   return true;
    141 }
    142 
    143 bool DbusSignature::GetArrayTypenameForSignature(
    144     string::const_iterator signature,
    145     string::const_iterator end,
    146     string::const_iterator* next,
    147     string* output) {
    148   string::const_iterator cur = signature;
    149   if (cur == end) {
    150     LOG(ERROR) << "At end of string while reading array parameter";
    151     return false;
    152   }
    153 
    154   if (*cur == DBUS_DICT_ENTRY_BEGIN_CHAR) {
    155     vector<string> children;
    156     ++cur;
    157     while (cur != end && *cur != DBUS_DICT_ENTRY_END_CHAR) {
    158       children.emplace_back();
    159       if (!GetTypenameForSignature(cur, end, &cur, &children.back())) {
    160         LOG(ERROR) << "Unable to decode child elements starting at "
    161                    << string(cur, end);
    162         return false;
    163       }
    164     }
    165     if (cur == end) {
    166       LOG(ERROR) << "At end of string while processing dict "
    167                  << "starting at " << string(signature, end);
    168       return false;
    169     }
    170 
    171     DCHECK_EQ(DBUS_DICT_ENTRY_END_CHAR, *cur);
    172     ++cur;
    173 
    174     if (children.size() != 2) {
    175       LOG(ERROR) << "Dict entry contains " << children.size()
    176                  << " members starting at " << string(signature, end)
    177                  << " where only 2 children is valid.";
    178       return false;
    179     }
    180     string dict_signature{signature, cur};
    181     if (dict_signature == "{sv}") {
    182       *output = kVariantDictTypename;
    183     } else {
    184       *output = StringPrintf("%s<%s, %s>", kDictTypename,
    185                              children[0].c_str(), children[1].c_str());
    186     }
    187   } else {
    188     string child;
    189     if (!GetTypenameForSignature(cur, end, &cur, &child)) {
    190       LOG(ERROR) << "Unable to decode child element starting at "
    191                  << string(cur, end);
    192       return false;
    193     }
    194     *output = StringPrintf("%s<%s>", kArrayTypename, child.c_str());
    195   }
    196 
    197   if (next) {
    198     *next = cur;
    199   }
    200 
    201   return true;
    202 }
    203 
    204 bool DbusSignature::GetStructTypenameForSignature(
    205     string::const_iterator signature,
    206     string::const_iterator end,
    207     string::const_iterator* next,
    208     string* output) {
    209   string::const_iterator cur = signature;
    210   if (cur == end) {
    211     LOG(ERROR) << "At end of string while reading struct parameter";
    212     return false;
    213   }
    214 
    215   vector<string> children;
    216   while (cur != end && *cur != DBUS_STRUCT_END_CHAR) {
    217     children.emplace_back();
    218     if (!GetTypenameForSignature(cur, end, &cur, &children.back())) {
    219       LOG(ERROR) << "Unable to decode child elements starting at "
    220                  << string(cur, end);
    221       return false;
    222     }
    223   }
    224   if (cur == end) {
    225     LOG(ERROR) << "At end of string while processing struct "
    226                << "starting at " << string(signature, end);
    227     return false;
    228   }
    229 
    230   DCHECK_EQ(DBUS_STRUCT_END_CHAR, *cur);
    231   ++cur;
    232 
    233   *output = StringPrintf("%s<%s>", kTupleTypename,
    234                          brillo::string_utils::Join(", ", children).c_str());
    235 
    236   if (next) {
    237     *next = cur;
    238   }
    239 
    240   return true;
    241 }
    242 
    243 }  // namespace chromeos_dbus_bindings
    244