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