1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "dbus/values_util.h"
10 #include "base/json/json_writer.h"
11 #include "base/logging.h"
12 #include "base/memory/raw_ptr.h"
13 #include "base/notreached.h"
14 #include "base/values.h"
15 #include "dbus/message.h"
21 // Returns whether |value| is exactly representable by double or not.
23 bool IsExactlyRepresentableByDouble(T value) {
24 return value == static_cast<T>(static_cast<double>(value));
27 // Pops values from |reader| and appends them to |list_value|.
28 bool PopListElements(MessageReader* reader, base::Value::List& list_value) {
29 while (reader->HasMoreData()) {
30 base::Value element_value = PopDataAsValue(reader);
31 if (element_value.is_none())
33 list_value.Append(std::move(element_value));
38 // Pops dict-entries from |reader| and sets them to |dictionary_value|
39 bool PopDictionaryEntries(MessageReader* reader,
40 base::Value::Dict& dictionary_value) {
41 while (reader->HasMoreData()) {
42 DCHECK_EQ(Message::DICT_ENTRY, reader->GetDataType());
43 MessageReader entry_reader(nullptr);
44 if (!reader->PopDictEntry(&entry_reader))
46 // Get key as a string.
47 std::string key_string;
48 if (entry_reader.GetDataType() == Message::STRING) {
49 // If the type of keys is STRING, pop it directly.
50 if (!entry_reader.PopString(&key_string))
53 // If the type of keys is not STRING, convert it to string.
54 base::Value key = PopDataAsValue(&entry_reader);
57 // Use JSONWriter to convert an arbitrary value to a string.
58 base::JSONWriter::Write(key, &key_string);
60 // Get the value and set the key-value pair.
61 base::Value value = PopDataAsValue(&entry_reader);
64 dictionary_value.Set(key_string, std::move(value));
69 // Gets the D-Bus type signature for the value.
70 std::string GetTypeSignature(base::ValueView value) {
72 std::string operator()(absl::monostate) {
73 DLOG(ERROR) << "Unexpected type " << base::Value::Type::NONE;
77 std::string operator()(bool) { return "b"; }
79 std::string operator()(int) { return "i"; }
81 std::string operator()(double) { return "d"; }
83 std::string operator()(base::StringPiece) { return "s"; }
85 std::string operator()(const base::Value::BlobStorage&) { return "ay"; }
87 std::string operator()(const base::Value::Dict&) { return "a{sv}"; }
89 std::string operator()(const base::Value::List&) { return "av"; }
91 return value.Visit(Visitor());
96 base::Value PopDataAsValue(MessageReader* reader) {
98 switch (reader->GetDataType()) {
99 case Message::INVALID_DATA:
102 case Message::BYTE: {
104 if (reader->PopByte(&value))
105 result = base::Value(value);
108 case Message::BOOL: {
110 if (reader->PopBool(&value))
111 result = base::Value(value);
114 case Message::INT16: {
116 if (reader->PopInt16(&value))
117 result = base::Value(value);
120 case Message::UINT16: {
122 if (reader->PopUint16(&value))
123 result = base::Value(value);
126 case Message::INT32: {
128 if (reader->PopInt32(&value))
129 result = base::Value(value);
132 case Message::UINT32: {
134 if (reader->PopUint32(&value)) {
135 result = base::Value(static_cast<double>(value));
139 case Message::INT64: {
141 if (reader->PopInt64(&value)) {
142 DLOG_IF(WARNING, !IsExactlyRepresentableByDouble(value))
143 << value << " is not exactly representable by double";
144 result = base::Value(static_cast<double>(value));
148 case Message::UINT64: {
150 if (reader->PopUint64(&value)) {
151 DLOG_IF(WARNING, !IsExactlyRepresentableByDouble(value))
152 << value << " is not exactly representable by double";
153 result = base::Value(static_cast<double>(value));
157 case Message::DOUBLE: {
159 if (reader->PopDouble(&value))
160 result = base::Value(value);
163 case Message::STRING: {
165 if (reader->PopString(&value))
166 result = base::Value(value);
169 case Message::OBJECT_PATH: {
171 if (reader->PopObjectPath(&value))
172 result = base::Value(value.value());
175 case Message::UNIX_FD: {
176 // Cannot distinguish a file descriptor from an int
180 case Message::ARRAY: {
181 MessageReader sub_reader(nullptr);
182 if (reader->PopArray(&sub_reader)) {
183 // If the type of the array's element is DICT_ENTRY, create a
184 // Value with type base::Value::Dict, otherwise create a
185 // Value with type base::Value::List.
186 if (sub_reader.GetDataType() == Message::DICT_ENTRY) {
187 base::Value::Dict dictionary_value;
188 if (PopDictionaryEntries(&sub_reader, dictionary_value))
189 result = base::Value(std::move(dictionary_value));
191 base::Value::List list_value;
192 if (PopListElements(&sub_reader, list_value))
193 result = base::Value(std::move(list_value));
198 case Message::STRUCT: {
199 MessageReader sub_reader(nullptr);
200 if (reader->PopStruct(&sub_reader)) {
201 base::Value::List list_value;
202 if (PopListElements(&sub_reader, list_value))
203 result = base::Value(std::move(list_value));
207 case Message::DICT_ENTRY:
208 // DICT_ENTRY must be popped as an element of an array.
211 case Message::VARIANT: {
212 MessageReader sub_reader(nullptr);
213 if (reader->PopVariant(&sub_reader))
214 result = PopDataAsValue(&sub_reader);
221 void AppendBasicTypeValueData(MessageWriter* writer, base::ValueView value) {
223 raw_ptr<MessageWriter> writer;
225 void operator()(absl::monostate) {
226 DLOG(ERROR) << "Unexpected type: " << base::Value::Type::NONE;
229 void operator()(bool value) { writer->AppendBool(value); }
231 void operator()(int value) { writer->AppendInt32(value); }
233 void operator()(double value) { writer->AppendDouble(value); }
235 void operator()(base::StringPiece value) { writer->AppendString(value); }
237 void operator()(const base::Value::BlobStorage&) {
238 DLOG(ERROR) << "Unexpected type: " << base::Value::Type::BINARY;
241 void operator()(const base::Value::Dict&) {
242 DLOG(ERROR) << "Unexpected type: " << base::Value::Type::DICT;
245 void operator()(const base::Value::List&) {
246 DLOG(ERROR) << "Unexpected type: " << base::Value::Type::LIST;
250 value.Visit(Visitor{.writer = writer});
253 void AppendBasicTypeValueDataAsVariant(MessageWriter* writer,
254 base::ValueView value) {
255 MessageWriter sub_writer(nullptr);
256 writer->OpenVariant(GetTypeSignature(value), &sub_writer);
257 AppendBasicTypeValueData(&sub_writer, value);
258 writer->CloseContainer(&sub_writer);
261 void AppendValueData(MessageWriter* writer, base::ValueView value) {
263 raw_ptr<MessageWriter> writer;
265 void operator()(absl::monostate) {
266 DLOG(ERROR) << "Unexpected type: " << base::Value::Type::NONE;
269 void operator()(bool value) {
270 return AppendBasicTypeValueData(writer, value);
273 void operator()(int value) {
274 return AppendBasicTypeValueData(writer, value);
277 void operator()(double value) {
278 return AppendBasicTypeValueData(writer, value);
281 void operator()(base::StringPiece value) {
282 return AppendBasicTypeValueData(writer, value);
285 void operator()(const base::Value::BlobStorage& value) {
286 DLOG(ERROR) << "Unexpected type: " << base::Value::Type::BINARY;
289 void operator()(const base::Value::Dict& value) {
290 dbus::MessageWriter array_writer(nullptr);
291 writer->OpenArray("{sv}", &array_writer);
292 for (auto item : value) {
293 dbus::MessageWriter dict_entry_writer(nullptr);
294 array_writer.OpenDictEntry(&dict_entry_writer);
295 dict_entry_writer.AppendString(item.first);
296 AppendValueDataAsVariant(&dict_entry_writer, item.second);
297 array_writer.CloseContainer(&dict_entry_writer);
299 writer->CloseContainer(&array_writer);
302 void operator()(const base::Value::List& value) {
303 dbus::MessageWriter array_writer(nullptr);
304 writer->OpenArray("v", &array_writer);
305 for (const auto& value_in_list : value) {
306 AppendValueDataAsVariant(&array_writer, value_in_list);
308 writer->CloseContainer(&array_writer);
312 value.Visit(Visitor{.writer = writer});
315 void AppendValueDataAsVariant(MessageWriter* writer, base::ValueView value) {
316 MessageWriter variant_writer(nullptr);
317 writer->OpenVariant(GetTypeSignature(value), &variant_writer);
318 AppendValueData(&variant_writer, value);
319 writer->CloseContainer(&variant_writer);