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
DbusSignature()37 DbusSignature::DbusSignature()
38 : object_path_typename_(kDefaultObjectPathTypename) {}
39
Parse(const string & signature,string * output)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
GetTypenameForSignature(string::const_iterator signature,string::const_iterator end,string::const_iterator * next,string * output)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
GetArrayTypenameForSignature(string::const_iterator signature,string::const_iterator end,string::const_iterator * next,string * output)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
GetStructTypenameForSignature(string::const_iterator signature,string::const_iterator end,string::const_iterator * next,string * output)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