| // Copyright 2014 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <brillo/dbus/data_serialization.h> |
| |
| #include <base/logging.h> |
| #include <brillo/any.h> |
| #include <brillo/variant_dictionary.h> |
| |
| namespace brillo { |
| namespace dbus_utils { |
| |
| void AppendValueToWriter(dbus::MessageWriter* writer, bool value) { |
| writer->AppendBool(value); |
| } |
| |
| void AppendValueToWriter(dbus::MessageWriter* writer, uint8_t value) { |
| writer->AppendByte(value); |
| } |
| |
| void AppendValueToWriter(dbus::MessageWriter* writer, int16_t value) { |
| writer->AppendInt16(value); |
| } |
| |
| void AppendValueToWriter(dbus::MessageWriter* writer, uint16_t value) { |
| writer->AppendUint16(value); |
| } |
| |
| void AppendValueToWriter(dbus::MessageWriter* writer, int32_t value) { |
| writer->AppendInt32(value); |
| } |
| |
| void AppendValueToWriter(dbus::MessageWriter* writer, uint32_t value) { |
| writer->AppendUint32(value); |
| } |
| |
| void AppendValueToWriter(dbus::MessageWriter* writer, int64_t value) { |
| writer->AppendInt64(value); |
| } |
| |
| void AppendValueToWriter(dbus::MessageWriter* writer, uint64_t value) { |
| writer->AppendUint64(value); |
| } |
| |
| void AppendValueToWriter(dbus::MessageWriter* writer, double value) { |
| writer->AppendDouble(value); |
| } |
| |
| void AppendValueToWriter(dbus::MessageWriter* writer, |
| const std::string& value) { |
| writer->AppendString(value); |
| } |
| |
| void AppendValueToWriter(dbus::MessageWriter* writer, const char* value) { |
| AppendValueToWriter(writer, std::string(value)); |
| } |
| |
| void AppendValueToWriter(dbus::MessageWriter* writer, |
| const dbus::ObjectPath& value) { |
| writer->AppendObjectPath(value); |
| } |
| |
| void AppendValueToWriter(dbus::MessageWriter* writer, |
| const dbus::FileDescriptor& value) { |
| writer->AppendFileDescriptor(value); |
| } |
| |
| void AppendValueToWriter(dbus::MessageWriter* writer, |
| const FileDescriptor& value) { |
| writer->AppendFileDescriptor(value.fd); |
| } |
| |
| void AppendValueToWriter(dbus::MessageWriter* writer, |
| const brillo::Any& value) { |
| value.AppendToDBusMessageWriter(writer); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| bool PopValueFromReader(dbus::MessageReader* reader, bool* value) { |
| dbus::MessageReader variant_reader(nullptr); |
| return details::DescendIntoVariantIfPresent(&reader, &variant_reader) && |
| reader->PopBool(value); |
| } |
| |
| bool PopValueFromReader(dbus::MessageReader* reader, uint8_t* value) { |
| dbus::MessageReader variant_reader(nullptr); |
| return details::DescendIntoVariantIfPresent(&reader, &variant_reader) && |
| reader->PopByte(value); |
| } |
| |
| bool PopValueFromReader(dbus::MessageReader* reader, int16_t* value) { |
| dbus::MessageReader variant_reader(nullptr); |
| return details::DescendIntoVariantIfPresent(&reader, &variant_reader) && |
| reader->PopInt16(value); |
| } |
| |
| bool PopValueFromReader(dbus::MessageReader* reader, uint16_t* value) { |
| dbus::MessageReader variant_reader(nullptr); |
| return details::DescendIntoVariantIfPresent(&reader, &variant_reader) && |
| reader->PopUint16(value); |
| } |
| |
| bool PopValueFromReader(dbus::MessageReader* reader, int32_t* value) { |
| dbus::MessageReader variant_reader(nullptr); |
| return details::DescendIntoVariantIfPresent(&reader, &variant_reader) && |
| reader->PopInt32(value); |
| } |
| |
| bool PopValueFromReader(dbus::MessageReader* reader, uint32_t* value) { |
| dbus::MessageReader variant_reader(nullptr); |
| return details::DescendIntoVariantIfPresent(&reader, &variant_reader) && |
| reader->PopUint32(value); |
| } |
| |
| bool PopValueFromReader(dbus::MessageReader* reader, int64_t* value) { |
| dbus::MessageReader variant_reader(nullptr); |
| return details::DescendIntoVariantIfPresent(&reader, &variant_reader) && |
| reader->PopInt64(value); |
| } |
| |
| bool PopValueFromReader(dbus::MessageReader* reader, uint64_t* value) { |
| dbus::MessageReader variant_reader(nullptr); |
| return details::DescendIntoVariantIfPresent(&reader, &variant_reader) && |
| reader->PopUint64(value); |
| } |
| |
| bool PopValueFromReader(dbus::MessageReader* reader, double* value) { |
| dbus::MessageReader variant_reader(nullptr); |
| return details::DescendIntoVariantIfPresent(&reader, &variant_reader) && |
| reader->PopDouble(value); |
| } |
| |
| bool PopValueFromReader(dbus::MessageReader* reader, std::string* value) { |
| dbus::MessageReader variant_reader(nullptr); |
| return details::DescendIntoVariantIfPresent(&reader, &variant_reader) && |
| reader->PopString(value); |
| } |
| |
| bool PopValueFromReader(dbus::MessageReader* reader, dbus::ObjectPath* value) { |
| dbus::MessageReader variant_reader(nullptr); |
| return details::DescendIntoVariantIfPresent(&reader, &variant_reader) && |
| reader->PopObjectPath(value); |
| } |
| |
| bool PopValueFromReader(dbus::MessageReader* reader, |
| dbus::FileDescriptor* value) { |
| dbus::MessageReader variant_reader(nullptr); |
| bool ok = details::DescendIntoVariantIfPresent(&reader, &variant_reader) && |
| reader->PopFileDescriptor(value); |
| if (ok) |
| value->CheckValidity(); |
| return ok; |
| } |
| |
| bool PopValueFromReader(dbus::MessageReader* reader, |
| base::ScopedFD* value) { |
| dbus::MessageReader variant_reader(nullptr); |
| return details::DescendIntoVariantIfPresent(&reader, &variant_reader) && |
| reader->PopFileDescriptor(value); |
| } |
| |
| namespace { |
| |
| // Helper methods for PopValueFromReader(dbus::MessageReader*, Any*) |
| // implementation. Pops a value of particular type from |reader| and assigns |
| // it to |value| of type Any. |
| template<typename T> |
| bool PopTypedValueFromReader(dbus::MessageReader* reader, |
| brillo::Any* value) { |
| T data{}; |
| if (!PopValueFromReader(reader, &data)) |
| return false; |
| *value = std::move(data); |
| return true; |
| } |
| |
| // std::vector<T> overload. |
| template<typename T> |
| bool PopTypedArrayFromReader(dbus::MessageReader* reader, |
| brillo::Any* value) { |
| return PopTypedValueFromReader<std::vector<T>>(reader, value); |
| } |
| |
| // std::map<KEY, VALUE> overload. |
| template<typename KEY, typename VALUE> |
| bool PopTypedMapFromReader(dbus::MessageReader* reader, brillo::Any* value) { |
| return PopTypedValueFromReader<std::map<KEY, VALUE>>(reader, value); |
| } |
| |
| // Helper methods for reading common ARRAY signatures into a Variant. |
| // Note that only common types are supported. If an additional specific |
| // type signature is required, feel free to add support for it. |
| bool PopArrayValueFromReader(dbus::MessageReader* reader, |
| brillo::Any* value) { |
| std::string signature = reader->GetDataSignature(); |
| if (signature == "ab") |
| return PopTypedArrayFromReader<bool>(reader, value); |
| else if (signature == "ay") |
| return PopTypedArrayFromReader<uint8_t>(reader, value); |
| else if (signature == "an") |
| return PopTypedArrayFromReader<int16_t>(reader, value); |
| else if (signature == "aq") |
| return PopTypedArrayFromReader<uint16_t>(reader, value); |
| else if (signature == "ai") |
| return PopTypedArrayFromReader<int32_t>(reader, value); |
| else if (signature == "au") |
| return PopTypedArrayFromReader<uint32_t>(reader, value); |
| else if (signature == "ax") |
| return PopTypedArrayFromReader<int64_t>(reader, value); |
| else if (signature == "at") |
| return PopTypedArrayFromReader<uint64_t>(reader, value); |
| else if (signature == "ad") |
| return PopTypedArrayFromReader<double>(reader, value); |
| else if (signature == "as") |
| return PopTypedArrayFromReader<std::string>(reader, value); |
| else if (signature == "ao") |
| return PopTypedArrayFromReader<dbus::ObjectPath>(reader, value); |
| else if (signature == "av") |
| return PopTypedArrayFromReader<brillo::Any>(reader, value); |
| else if (signature == "a{ss}") |
| return PopTypedMapFromReader<std::string, std::string>(reader, value); |
| else if (signature == "a{sv}") |
| return PopTypedValueFromReader<brillo::VariantDictionary>(reader, value); |
| else if (signature == "aa{ss}") |
| return PopTypedArrayFromReader< |
| std::map<std::string, std::string>>(reader, value); |
| else if (signature == "aa{sv}") |
| return PopTypedArrayFromReader<brillo::VariantDictionary>(reader, value); |
| else if (signature == "a{sa{ss}}") |
| return PopTypedMapFromReader< |
| std::string, std::map<std::string, std::string>>(reader, value); |
| else if (signature == "a{sa{sv}}") |
| return PopTypedMapFromReader< |
| std::string, brillo::VariantDictionary>(reader, value); |
| else if (signature == "a{say}") |
| return PopTypedMapFromReader< |
| std::string, std::vector<uint8_t>>(reader, value); |
| else if (signature == "a{uv}") |
| return PopTypedMapFromReader<uint32_t, brillo::Any>(reader, value); |
| else if (signature == "a(su)") |
| return PopTypedArrayFromReader< |
| std::tuple<std::string, uint32_t>>(reader, value); |
| else if (signature == "a{uu}") |
| return PopTypedMapFromReader<uint32_t, uint32_t>(reader, value); |
| else if (signature == "a(uu)") |
| return PopTypedArrayFromReader< |
| std::tuple<uint32_t, uint32_t>>(reader, value); |
| |
| // When a use case for particular array signature is found, feel free |
| // to add handing for it here. |
| LOG(ERROR) << "Variant de-serialization of array containing data of " |
| << "type '" << signature << "' is not yet supported"; |
| return false; |
| } |
| |
| // Helper methods for reading common STRUCT signatures into a Variant. |
| // Note that only common types are supported. If an additional specific |
| // type signature is required, feel free to add support for it. |
| bool PopStructValueFromReader(dbus::MessageReader* reader, |
| brillo::Any* value) { |
| std::string signature = reader->GetDataSignature(); |
| if (signature == "(ii)") |
| return PopTypedValueFromReader<std::tuple<int, int>>(reader, value); |
| else if (signature == "(ss)") |
| return PopTypedValueFromReader<std::tuple<std::string, std::string>>(reader, |
| value); |
| else if (signature == "(ub)") |
| return PopTypedValueFromReader<std::tuple<uint32_t, bool>>(reader, value); |
| else if (signature == "(uu)") |
| return PopTypedValueFromReader<std::tuple<uint32_t, uint32_t>>(reader, |
| value); |
| |
| // When a use case for particular struct signature is found, feel free |
| // to add handing for it here. |
| LOG(ERROR) << "Variant de-serialization of structs of type '" << signature |
| << "' is not yet supported"; |
| return false; |
| } |
| |
| } // anonymous namespace |
| |
| bool PopValueFromReader(dbus::MessageReader* reader, brillo::Any* value) { |
| dbus::MessageReader variant_reader(nullptr); |
| if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader)) |
| return false; |
| |
| switch (reader->GetDataType()) { |
| case dbus::Message::BYTE: |
| return PopTypedValueFromReader<uint8_t>(reader, value); |
| case dbus::Message::BOOL: |
| return PopTypedValueFromReader<bool>(reader, value); |
| case dbus::Message::INT16: |
| return PopTypedValueFromReader<int16_t>(reader, value); |
| case dbus::Message::UINT16: |
| return PopTypedValueFromReader<uint16_t>(reader, value); |
| case dbus::Message::INT32: |
| return PopTypedValueFromReader<int32_t>(reader, value); |
| case dbus::Message::UINT32: |
| return PopTypedValueFromReader<uint32_t>(reader, value); |
| case dbus::Message::INT64: |
| return PopTypedValueFromReader<int64_t>(reader, value); |
| case dbus::Message::UINT64: |
| return PopTypedValueFromReader<uint64_t>(reader, value); |
| case dbus::Message::DOUBLE: |
| return PopTypedValueFromReader<double>(reader, value); |
| case dbus::Message::STRING: |
| return PopTypedValueFromReader<std::string>(reader, value); |
| case dbus::Message::OBJECT_PATH: |
| return PopTypedValueFromReader<dbus::ObjectPath>(reader, value); |
| case dbus::Message::ARRAY: |
| return PopArrayValueFromReader(reader, value); |
| case dbus::Message::STRUCT: |
| return PopStructValueFromReader(reader, value); |
| case dbus::Message::DICT_ENTRY: |
| LOG(ERROR) << "Variant of DICT_ENTRY is invalid"; |
| return false; |
| case dbus::Message::VARIANT: |
| LOG(ERROR) << "Variant containing a variant is invalid"; |
| return false; |
| case dbus::Message::UNIX_FD: |
| CHECK(dbus::IsDBusTypeUnixFdSupported()) << "UNIX_FD data not supported"; |
| // dbus::FileDescriptor is not a copyable type. Cannot be returned via |
| // brillo::Any. Fail here. |
| LOG(ERROR) << "Cannot return FileDescriptor via Any"; |
| return false; |
| default: |
| LOG(FATAL) << "Unknown D-Bus data type: " << variant_reader.GetDataType(); |
| return false; |
| } |
| return true; |
| } |
| |
| } // namespace dbus_utils |
| } // namespace brillo |