123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323 |
- // Copyright (c) 2012 The Chromium 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 "dbus/values_util.h"
- #include <memory>
- #include <utility>
- #include "base/json/json_writer.h"
- #include "base/logging.h"
- #include "base/notreached.h"
- #include "base/values.h"
- #include "dbus/message.h"
- namespace dbus {
- namespace {
- // Returns whether |value| is exactly representable by double or not.
- template <typename T>
- bool IsExactlyRepresentableByDouble(T value) {
- return value == static_cast<T>(static_cast<double>(value));
- }
- // Pops values from |reader| and appends them to |list_value|.
- bool PopListElements(MessageReader* reader, base::Value* list_value) {
- DCHECK(list_value->is_list());
- while (reader->HasMoreData()) {
- base::Value element_value = PopDataAsValue(reader);
- if (element_value.is_none())
- return false;
- list_value->Append(std::move(element_value));
- }
- return true;
- }
- // Pops dict-entries from |reader| and sets them to |dictionary_value|
- bool PopDictionaryEntries(MessageReader* reader,
- base::Value* dictionary_value) {
- DCHECK(dictionary_value->is_dict());
- while (reader->HasMoreData()) {
- DCHECK_EQ(Message::DICT_ENTRY, reader->GetDataType());
- MessageReader entry_reader(nullptr);
- if (!reader->PopDictEntry(&entry_reader))
- return false;
- // Get key as a string.
- std::string key_string;
- if (entry_reader.GetDataType() == Message::STRING) {
- // If the type of keys is STRING, pop it directly.
- if (!entry_reader.PopString(&key_string))
- return false;
- } else {
- // If the type of keys is not STRING, convert it to string.
- base::Value key = PopDataAsValue(&entry_reader);
- if (key.is_none())
- return false;
- // Use JSONWriter to convert an arbitrary value to a string.
- base::JSONWriter::Write(key, &key_string);
- }
- // Get the value and set the key-value pair.
- base::Value value = PopDataAsValue(&entry_reader);
- if (value.is_none())
- return false;
- dictionary_value->SetKey(key_string, std::move(value));
- }
- return true;
- }
- // Gets the D-Bus type signature for the value.
- std::string GetTypeSignature(base::ValueView value) {
- struct Visitor {
- std::string operator()(absl::monostate) {
- DLOG(ERROR) << "Unexpected type " << base::Value::Type::NONE;
- return std::string();
- }
- std::string operator()(bool) { return "b"; }
- std::string operator()(int) { return "i"; }
- std::string operator()(double) { return "d"; }
- std::string operator()(base::StringPiece) { return "s"; }
- std::string operator()(const base::Value::BlobStorage&) { return "ay"; }
- std::string operator()(const base::Value::Dict&) { return "a{sv}"; }
- std::string operator()(const base::Value::List&) { return "av"; }
- };
- return value.Visit(Visitor());
- }
- } // namespace
- base::Value PopDataAsValue(MessageReader* reader) {
- base::Value result;
- switch (reader->GetDataType()) {
- case Message::INVALID_DATA:
- // Do nothing.
- break;
- case Message::BYTE: {
- uint8_t value = 0;
- if (reader->PopByte(&value))
- result = base::Value(value);
- break;
- }
- case Message::BOOL: {
- bool value = false;
- if (reader->PopBool(&value))
- result = base::Value(value);
- break;
- }
- case Message::INT16: {
- int16_t value = 0;
- if (reader->PopInt16(&value))
- result = base::Value(value);
- break;
- }
- case Message::UINT16: {
- uint16_t value = 0;
- if (reader->PopUint16(&value))
- result = base::Value(value);
- break;
- }
- case Message::INT32: {
- int32_t value = 0;
- if (reader->PopInt32(&value))
- result = base::Value(value);
- break;
- }
- case Message::UINT32: {
- uint32_t value = 0;
- if (reader->PopUint32(&value)) {
- result = base::Value(static_cast<double>(value));
- }
- break;
- }
- case Message::INT64: {
- int64_t value = 0;
- if (reader->PopInt64(&value)) {
- DLOG_IF(WARNING, !IsExactlyRepresentableByDouble(value))
- << value << " is not exactly representable by double";
- result = base::Value(static_cast<double>(value));
- }
- break;
- }
- case Message::UINT64: {
- uint64_t value = 0;
- if (reader->PopUint64(&value)) {
- DLOG_IF(WARNING, !IsExactlyRepresentableByDouble(value))
- << value << " is not exactly representable by double";
- result = base::Value(static_cast<double>(value));
- }
- break;
- }
- case Message::DOUBLE: {
- double value = 0;
- if (reader->PopDouble(&value))
- result = base::Value(value);
- break;
- }
- case Message::STRING: {
- std::string value;
- if (reader->PopString(&value))
- result = base::Value(value);
- break;
- }
- case Message::OBJECT_PATH: {
- ObjectPath value;
- if (reader->PopObjectPath(&value))
- result = base::Value(value.value());
- break;
- }
- case Message::UNIX_FD: {
- // Cannot distinguish a file descriptor from an int
- NOTREACHED();
- break;
- }
- case Message::ARRAY: {
- MessageReader sub_reader(nullptr);
- if (reader->PopArray(&sub_reader)) {
- // If the type of the array's element is DICT_ENTRY, create a
- // Value with type base::Value::Type::DICTIONARY, otherwise create a
- // Value with type base::Value::Type::LIST.
- if (sub_reader.GetDataType() == Message::DICT_ENTRY) {
- auto dictionary_value = base::Value(base::Value::Type::DICTIONARY);
- if (PopDictionaryEntries(&sub_reader, &dictionary_value))
- result = std::move(dictionary_value);
- } else {
- auto list_value = base::Value(base::Value::Type::LIST);
- if (PopListElements(&sub_reader, &list_value))
- result = std::move(list_value);
- }
- }
- break;
- }
- case Message::STRUCT: {
- MessageReader sub_reader(nullptr);
- if (reader->PopStruct(&sub_reader)) {
- auto list_value = base::Value(base::Value::Type::LIST);
- if (PopListElements(&sub_reader, &list_value))
- result = std::move(list_value);
- }
- break;
- }
- case Message::DICT_ENTRY:
- // DICT_ENTRY must be popped as an element of an array.
- NOTREACHED();
- break;
- case Message::VARIANT: {
- MessageReader sub_reader(nullptr);
- if (reader->PopVariant(&sub_reader))
- result = PopDataAsValue(&sub_reader);
- break;
- }
- }
- return result;
- }
- void AppendBasicTypeValueData(MessageWriter* writer, base::ValueView value) {
- struct Visitor {
- MessageWriter* writer;
- void operator()(absl::monostate) {
- DLOG(ERROR) << "Unexpected type: " << base::Value::Type::NONE;
- }
- void operator()(bool value) { writer->AppendBool(value); }
- void operator()(int value) { writer->AppendInt32(value); }
- void operator()(double value) { writer->AppendDouble(value); }
- void operator()(base::StringPiece value) { writer->AppendString(value); }
- void operator()(const base::Value::BlobStorage&) {
- DLOG(ERROR) << "Unexpected type: " << base::Value::Type::BINARY;
- }
- void operator()(const base::Value::Dict&) {
- DLOG(ERROR) << "Unexpected type: " << base::Value::Type::DICT;
- }
- void operator()(const base::Value::List&) {
- DLOG(ERROR) << "Unexpected type: " << base::Value::Type::LIST;
- }
- };
- value.Visit(Visitor{.writer = writer});
- }
- void AppendBasicTypeValueDataAsVariant(MessageWriter* writer,
- base::ValueView value) {
- MessageWriter sub_writer(nullptr);
- writer->OpenVariant(GetTypeSignature(value), &sub_writer);
- AppendBasicTypeValueData(&sub_writer, value);
- writer->CloseContainer(&sub_writer);
- }
- void AppendValueData(MessageWriter* writer, base::ValueView value) {
- struct Visitor {
- MessageWriter* writer;
- void operator()(absl::monostate) {
- DLOG(ERROR) << "Unexpected type: " << base::Value::Type::NONE;
- }
- void operator()(bool value) {
- return AppendBasicTypeValueData(writer, value);
- }
- void operator()(int value) {
- return AppendBasicTypeValueData(writer, value);
- }
- void operator()(double value) {
- return AppendBasicTypeValueData(writer, value);
- }
- void operator()(base::StringPiece value) {
- return AppendBasicTypeValueData(writer, value);
- }
- void operator()(const base::Value::BlobStorage& value) {
- DLOG(ERROR) << "Unexpected type: " << base::Value::Type::BINARY;
- }
- void operator()(const base::Value::Dict& value) {
- dbus::MessageWriter array_writer(nullptr);
- writer->OpenArray("{sv}", &array_writer);
- for (auto item : value) {
- dbus::MessageWriter dict_entry_writer(nullptr);
- array_writer.OpenDictEntry(&dict_entry_writer);
- dict_entry_writer.AppendString(item.first);
- AppendValueDataAsVariant(&dict_entry_writer, item.second);
- array_writer.CloseContainer(&dict_entry_writer);
- }
- writer->CloseContainer(&array_writer);
- }
- void operator()(const base::Value::List& value) {
- dbus::MessageWriter array_writer(nullptr);
- writer->OpenArray("v", &array_writer);
- for (const auto& value_in_list : value) {
- AppendValueDataAsVariant(&array_writer, value_in_list);
- }
- writer->CloseContainer(&array_writer);
- }
- };
- value.Visit(Visitor{.writer = writer});
- }
- void AppendValueDataAsVariant(MessageWriter* writer, base::ValueView value) {
- MessageWriter variant_writer(nullptr);
- writer->OpenVariant(GetTypeSignature(value), &variant_writer);
- AppendValueData(&variant_writer, value);
- writer->CloseContainer(&variant_writer);
- }
- } // namespace dbus
|