// 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 base::ScopedFD& value) {
writer->AppendFileDescriptor(value.get());
}
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,
base::ScopedFD* value) {
dbus::MessageReader variant_reader(nullptr);
bool ok = details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
reader->PopFileDescriptor(value);
return ok;
}
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";
// base::ScopedFD 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