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 <brillo/dbus/data_serialization.h>
6
7#include <base/logging.h>
8#include <brillo/any.h>
9#include <brillo/variant_dictionary.h>
10
11namespace brillo {
12namespace dbus_utils {
13
14void AppendValueToWriter(dbus::MessageWriter* writer, bool value) {
15  writer->AppendBool(value);
16}
17
18void AppendValueToWriter(dbus::MessageWriter* writer, uint8_t value) {
19  writer->AppendByte(value);
20}
21
22void AppendValueToWriter(dbus::MessageWriter* writer, int16_t value) {
23  writer->AppendInt16(value);
24}
25
26void AppendValueToWriter(dbus::MessageWriter* writer, uint16_t value) {
27  writer->AppendUint16(value);
28}
29
30void AppendValueToWriter(dbus::MessageWriter* writer, int32_t value) {
31  writer->AppendInt32(value);
32}
33
34void AppendValueToWriter(dbus::MessageWriter* writer, uint32_t value) {
35  writer->AppendUint32(value);
36}
37
38void AppendValueToWriter(dbus::MessageWriter* writer, int64_t value) {
39  writer->AppendInt64(value);
40}
41
42void AppendValueToWriter(dbus::MessageWriter* writer, uint64_t value) {
43  writer->AppendUint64(value);
44}
45
46void AppendValueToWriter(dbus::MessageWriter* writer, double value) {
47  writer->AppendDouble(value);
48}
49
50void AppendValueToWriter(dbus::MessageWriter* writer,
51                         const std::string& value) {
52  writer->AppendString(value);
53}
54
55void AppendValueToWriter(dbus::MessageWriter* writer, const char* value) {
56  AppendValueToWriter(writer, std::string(value));
57}
58
59void AppendValueToWriter(dbus::MessageWriter* writer,
60                         const dbus::ObjectPath& value) {
61  writer->AppendObjectPath(value);
62}
63
64void AppendValueToWriter(dbus::MessageWriter* writer,
65                         const dbus::FileDescriptor& value) {
66  writer->AppendFileDescriptor(value);
67}
68
69void AppendValueToWriter(dbus::MessageWriter* writer,
70                         const brillo::Any& value) {
71  value.AppendToDBusMessageWriter(writer);
72}
73
74///////////////////////////////////////////////////////////////////////////////
75
76bool PopValueFromReader(dbus::MessageReader* reader, bool* value) {
77  dbus::MessageReader variant_reader(nullptr);
78  return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
79         reader->PopBool(value);
80}
81
82bool PopValueFromReader(dbus::MessageReader* reader, uint8_t* value) {
83  dbus::MessageReader variant_reader(nullptr);
84  return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
85         reader->PopByte(value);
86}
87
88bool PopValueFromReader(dbus::MessageReader* reader, int16_t* value) {
89  dbus::MessageReader variant_reader(nullptr);
90  return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
91         reader->PopInt16(value);
92}
93
94bool PopValueFromReader(dbus::MessageReader* reader, uint16_t* value) {
95  dbus::MessageReader variant_reader(nullptr);
96  return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
97         reader->PopUint16(value);
98}
99
100bool PopValueFromReader(dbus::MessageReader* reader, int32_t* value) {
101  dbus::MessageReader variant_reader(nullptr);
102  return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
103         reader->PopInt32(value);
104}
105
106bool PopValueFromReader(dbus::MessageReader* reader, uint32_t* value) {
107  dbus::MessageReader variant_reader(nullptr);
108  return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
109         reader->PopUint32(value);
110}
111
112bool PopValueFromReader(dbus::MessageReader* reader, int64_t* value) {
113  dbus::MessageReader variant_reader(nullptr);
114  return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
115         reader->PopInt64(value);
116}
117
118bool PopValueFromReader(dbus::MessageReader* reader, uint64_t* value) {
119  dbus::MessageReader variant_reader(nullptr);
120  return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
121         reader->PopUint64(value);
122}
123
124bool PopValueFromReader(dbus::MessageReader* reader, double* value) {
125  dbus::MessageReader variant_reader(nullptr);
126  return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
127         reader->PopDouble(value);
128}
129
130bool PopValueFromReader(dbus::MessageReader* reader, std::string* value) {
131  dbus::MessageReader variant_reader(nullptr);
132  return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
133         reader->PopString(value);
134}
135
136bool PopValueFromReader(dbus::MessageReader* reader, dbus::ObjectPath* value) {
137  dbus::MessageReader variant_reader(nullptr);
138  return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
139         reader->PopObjectPath(value);
140}
141
142bool PopValueFromReader(dbus::MessageReader* reader,
143                        dbus::FileDescriptor* value) {
144  dbus::MessageReader variant_reader(nullptr);
145  bool ok = details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
146            reader->PopFileDescriptor(value);
147  if (ok)
148    value->CheckValidity();
149  return ok;
150}
151
152namespace {
153
154// Helper methods for PopValueFromReader(dbus::MessageReader*, Any*)
155// implementation. Pops a value of particular type from |reader| and assigns
156// it to |value| of type Any.
157template<typename T>
158bool PopTypedValueFromReader(dbus::MessageReader* reader,
159                             brillo::Any* value) {
160  T data{};
161  if (!PopValueFromReader(reader, &data))
162    return false;
163  *value = std::move(data);
164  return true;
165}
166
167// std::vector<T> overload.
168template<typename T>
169bool PopTypedArrayFromReader(dbus::MessageReader* reader,
170                             brillo::Any* value) {
171  return PopTypedValueFromReader<std::vector<T>>(reader, value);
172}
173
174// std::map<KEY, VALUE> overload.
175template<typename KEY, typename VALUE>
176bool PopTypedMapFromReader(dbus::MessageReader* reader, brillo::Any* value) {
177  return PopTypedValueFromReader<std::map<KEY, VALUE>>(reader, value);
178}
179
180// Helper methods for reading common ARRAY signatures into a Variant.
181// Note that only common types are supported. If an additional specific
182// type signature is required, feel free to add support for it.
183bool PopArrayValueFromReader(dbus::MessageReader* reader,
184                             brillo::Any* value) {
185  std::string signature = reader->GetDataSignature();
186  if (signature == "ab")
187    return PopTypedArrayFromReader<bool>(reader, value);
188  else if (signature == "ay")
189    return PopTypedArrayFromReader<uint8_t>(reader, value);
190  else if (signature == "an")
191    return PopTypedArrayFromReader<int16_t>(reader, value);
192  else if (signature == "aq")
193    return PopTypedArrayFromReader<uint16_t>(reader, value);
194  else if (signature == "ai")
195    return PopTypedArrayFromReader<int32_t>(reader, value);
196  else if (signature == "au")
197    return PopTypedArrayFromReader<uint32_t>(reader, value);
198  else if (signature == "ax")
199    return PopTypedArrayFromReader<int64_t>(reader, value);
200  else if (signature == "at")
201    return PopTypedArrayFromReader<uint64_t>(reader, value);
202  else if (signature == "ad")
203    return PopTypedArrayFromReader<double>(reader, value);
204  else if (signature == "as")
205    return PopTypedArrayFromReader<std::string>(reader, value);
206  else if (signature == "ao")
207    return PopTypedArrayFromReader<dbus::ObjectPath>(reader, value);
208  else if (signature == "av")
209    return PopTypedArrayFromReader<brillo::Any>(reader, value);
210  else if (signature == "a{ss}")
211    return PopTypedMapFromReader<std::string, std::string>(reader, value);
212  else if (signature == "a{sv}")
213    return PopTypedValueFromReader<brillo::VariantDictionary>(reader, value);
214  else if (signature == "aa{sv}")
215    return PopTypedArrayFromReader<brillo::VariantDictionary>(reader, value);
216  else if (signature == "a{sa{ss}}")
217    return PopTypedMapFromReader<
218        std::string, std::map<std::string, std::string>>(reader, value);
219  else if (signature == "a{sa{sv}}")
220    return PopTypedMapFromReader<
221        std::string, brillo::VariantDictionary>(reader, value);
222  else if (signature == "a{say}")
223    return PopTypedMapFromReader<
224        std::string, std::vector<uint8_t>>(reader, value);
225  else if (signature == "a{uv}")
226    return PopTypedMapFromReader<uint32_t, brillo::Any>(reader, value);
227  else if (signature == "a(su)")
228    return PopTypedArrayFromReader<
229        std::tuple<std::string, uint32_t>>(reader, value);
230  else if (signature == "a{uu}")
231    return PopTypedMapFromReader<uint32_t, uint32_t>(reader, value);
232  else if (signature == "a(uu)")
233    return PopTypedArrayFromReader<
234        std::tuple<uint32_t, uint32_t>>(reader, value);
235
236  // When a use case for particular array signature is found, feel free
237  // to add handing for it here.
238  LOG(ERROR) << "Variant de-serialization of array containing data of "
239             << "type '" << signature << "' is not yet supported";
240  return false;
241}
242
243// Helper methods for reading common STRUCT signatures into a Variant.
244// Note that only common types are supported. If an additional specific
245// type signature is required, feel free to add support for it.
246bool PopStructValueFromReader(dbus::MessageReader* reader,
247                              brillo::Any* value) {
248  std::string signature = reader->GetDataSignature();
249  if (signature == "(ii)")
250    return PopTypedValueFromReader<std::tuple<int, int>>(reader, value);
251  else if (signature == "(ss)")
252    return PopTypedValueFromReader<std::tuple<std::string, std::string>>(reader,
253                                                                         value);
254  else if (signature == "(ub)")
255    return PopTypedValueFromReader<std::tuple<uint32_t, bool>>(reader, value);
256  else if (signature == "(uu)")
257    return PopTypedValueFromReader<std::tuple<uint32_t, uint32_t>>(reader,
258                                                                   value);
259
260  // When a use case for particular struct signature is found, feel free
261  // to add handing for it here.
262  LOG(ERROR) << "Variant de-serialization of structs of type '" << signature
263             << "' is not yet supported";
264  return false;
265}
266
267}  // anonymous namespace
268
269bool PopValueFromReader(dbus::MessageReader* reader, brillo::Any* value) {
270  dbus::MessageReader variant_reader(nullptr);
271  if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader))
272    return false;
273
274  switch (reader->GetDataType()) {
275    case dbus::Message::BYTE:
276      return PopTypedValueFromReader<uint8_t>(reader, value);
277    case dbus::Message::BOOL:
278      return PopTypedValueFromReader<bool>(reader, value);
279    case dbus::Message::INT16:
280      return PopTypedValueFromReader<int16_t>(reader, value);
281    case dbus::Message::UINT16:
282      return PopTypedValueFromReader<uint16_t>(reader, value);
283    case dbus::Message::INT32:
284      return PopTypedValueFromReader<int32_t>(reader, value);
285    case dbus::Message::UINT32:
286      return PopTypedValueFromReader<uint32_t>(reader, value);
287    case dbus::Message::INT64:
288      return PopTypedValueFromReader<int64_t>(reader, value);
289    case dbus::Message::UINT64:
290      return PopTypedValueFromReader<uint64_t>(reader, value);
291    case dbus::Message::DOUBLE:
292      return PopTypedValueFromReader<double>(reader, value);
293    case dbus::Message::STRING:
294      return PopTypedValueFromReader<std::string>(reader, value);
295    case dbus::Message::OBJECT_PATH:
296      return PopTypedValueFromReader<dbus::ObjectPath>(reader, value);
297    case dbus::Message::ARRAY:
298      return PopArrayValueFromReader(reader, value);
299    case dbus::Message::STRUCT:
300      return PopStructValueFromReader(reader, value);
301    case dbus::Message::DICT_ENTRY:
302      LOG(ERROR) << "Variant of DICT_ENTRY is invalid";
303      return false;
304    case dbus::Message::VARIANT:
305      LOG(ERROR) << "Variant containing a variant is invalid";
306      return false;
307    case dbus::Message::UNIX_FD:
308      CHECK(dbus::IsDBusTypeUnixFdSupported()) << "UNIX_FD data not supported";
309      // dbus::FileDescriptor is not a copyable type. Cannot be returned via
310      // brillo::Any. Fail here.
311      LOG(ERROR) << "Cannot return FileDescriptor via Any";
312      return false;
313    default:
314      LOG(FATAL) << "Unknown D-Bus data type: " << variant_reader.GetDataType();
315      return false;
316  }
317  return true;
318}
319
320}  // namespace dbus_utils
321}  // namespace brillo
322