blob: e57380d1fa7e0b1b3f0987b773ed71707210fc8f [file] [log] [blame]
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +09001// Copyright (c) 2012 The Chromium 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 "dbus/values_util.h"
6
dcheng6ad83f32016-05-30 15:33:58 +09007#include <utility>
dcheng30c5a172016-04-09 07:55:04 +09008
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +09009#include "base/json/json_writer.h"
10#include "base/logging.h"
dcheng6ad83f32016-05-30 15:33:58 +090011#include "base/memory/ptr_util.h"
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +090012#include "base/values.h"
13#include "dbus/message.h"
14
15namespace dbus {
16
17namespace {
18
19// Returns whether |value| is exactly representable by double or not.
20template<typename T>
21bool IsExactlyRepresentableByDouble(T value) {
22 return value == static_cast<T>(static_cast<double>(value));
23}
24
25// Pops values from |reader| and appends them to |list_value|.
thestig@chromium.orge1acdf82013-02-13 05:06:15 +090026bool PopListElements(MessageReader* reader, base::ListValue* list_value) {
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +090027 while (reader->HasMoreData()) {
dcheng6ad83f32016-05-30 15:33:58 +090028 std::unique_ptr<base::Value> element_value = PopDataAsValue(reader);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +090029 if (!element_value)
30 return false;
dcheng6ad83f32016-05-30 15:33:58 +090031 list_value->Append(std::move(element_value));
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +090032 }
33 return true;
34}
35
36// Pops dict-entries from |reader| and sets them to |dictionary_value|
37bool PopDictionaryEntries(MessageReader* reader,
thestig@chromium.orge1acdf82013-02-13 05:06:15 +090038 base::DictionaryValue* dictionary_value) {
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +090039 while (reader->HasMoreData()) {
40 DCHECK_EQ(Message::DICT_ENTRY, reader->GetDataType());
41 MessageReader entry_reader(NULL);
42 if (!reader->PopDictEntry(&entry_reader))
43 return false;
44 // Get key as a string.
45 std::string key_string;
46 if (entry_reader.GetDataType() == Message::STRING) {
47 // If the type of keys is STRING, pop it directly.
48 if (!entry_reader.PopString(&key_string))
49 return false;
50 } else {
51 // If the type of keys is not STRING, convert it to string.
dcheng30c5a172016-04-09 07:55:04 +090052 std::unique_ptr<base::Value> key(PopDataAsValue(&entry_reader));
estadeb5f30dd2015-05-16 10:02:34 +090053 if (!key)
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +090054 return false;
55 // Use JSONWriter to convert an arbitrary value to a string.
estadeb5f30dd2015-05-16 10:02:34 +090056 base::JSONWriter::Write(*key, &key_string);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +090057 }
58 // Get the value and set the key-value pair.
dcheng6ad83f32016-05-30 15:33:58 +090059 std::unique_ptr<base::Value> value = PopDataAsValue(&entry_reader);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +090060 if (!value)
61 return false;
dcheng6ad83f32016-05-30 15:33:58 +090062 dictionary_value->SetWithoutPathExpansion(key_string, std::move(value));
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +090063 }
64 return true;
65}
66
hashimoto@chromium.orgea599822012-03-25 05:37:18 +090067// Gets the D-Bus type signature for the value.
68std::string GetTypeSignature(const base::Value& value) {
69 switch (value.GetType()) {
jdoerrie89ee31a2016-12-08 00:43:28 +090070 case base::Value::Type::BOOLEAN:
hashimoto@chromium.orgea599822012-03-25 05:37:18 +090071 return "b";
jdoerrie89ee31a2016-12-08 00:43:28 +090072 case base::Value::Type::INTEGER:
hashimoto@chromium.orgea599822012-03-25 05:37:18 +090073 return "i";
jdoerrie89ee31a2016-12-08 00:43:28 +090074 case base::Value::Type::DOUBLE:
hashimoto@chromium.orgea599822012-03-25 05:37:18 +090075 return "d";
jdoerrie89ee31a2016-12-08 00:43:28 +090076 case base::Value::Type::STRING:
hashimoto@chromium.orgea599822012-03-25 05:37:18 +090077 return "s";
jdoerrie89ee31a2016-12-08 00:43:28 +090078 case base::Value::Type::BINARY:
hashimoto@chromium.orgea599822012-03-25 05:37:18 +090079 return "ay";
jdoerrie89ee31a2016-12-08 00:43:28 +090080 case base::Value::Type::DICTIONARY:
hashimoto@chromium.orgea599822012-03-25 05:37:18 +090081 return "a{sv}";
jdoerrie89ee31a2016-12-08 00:43:28 +090082 case base::Value::Type::LIST:
armansito@chromium.org39d51b92014-05-22 20:52:55 +090083 return "av";
hashimoto@chromium.orgea599822012-03-25 05:37:18 +090084 default:
85 DLOG(ERROR) << "Unexpected type " << value.GetType();
dcheng@chromium.org8164c2c2013-04-09 17:46:45 +090086 return std::string();
hashimoto@chromium.orgea599822012-03-25 05:37:18 +090087 }
88}
89
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +090090} // namespace
91
dcheng6ad83f32016-05-30 15:33:58 +090092std::unique_ptr<base::Value> PopDataAsValue(MessageReader* reader) {
93 std::unique_ptr<base::Value> result;
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +090094 switch (reader->GetDataType()) {
95 case Message::INVALID_DATA:
96 // Do nothing.
97 break;
98 case Message::BYTE: {
avi0ad0ce02015-12-23 03:12:45 +090099 uint8_t value = 0;
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900100 if (reader->PopByte(&value))
jdoerriebfe825e2017-03-02 21:09:19 +0900101 result = base::MakeUnique<base::Value>(value);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900102 break;
103 }
104 case Message::BOOL: {
105 bool value = false;
106 if (reader->PopBool(&value))
jdoerriebfe825e2017-03-02 21:09:19 +0900107 result = base::MakeUnique<base::Value>(value);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900108 break;
109 }
110 case Message::INT16: {
avi0ad0ce02015-12-23 03:12:45 +0900111 int16_t value = 0;
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900112 if (reader->PopInt16(&value))
jdoerriebfe825e2017-03-02 21:09:19 +0900113 result = base::MakeUnique<base::Value>(value);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900114 break;
115 }
116 case Message::UINT16: {
avi0ad0ce02015-12-23 03:12:45 +0900117 uint16_t value = 0;
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900118 if (reader->PopUint16(&value))
jdoerriebfe825e2017-03-02 21:09:19 +0900119 result = base::MakeUnique<base::Value>(value);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900120 break;
121 }
122 case Message::INT32: {
avi0ad0ce02015-12-23 03:12:45 +0900123 int32_t value = 0;
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900124 if (reader->PopInt32(&value))
jdoerriebfe825e2017-03-02 21:09:19 +0900125 result = base::MakeUnique<base::Value>(value);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900126 break;
127 }
128 case Message::UINT32: {
avi0ad0ce02015-12-23 03:12:45 +0900129 uint32_t value = 0;
dcheng6ad83f32016-05-30 15:33:58 +0900130 if (reader->PopUint32(&value)) {
jdoerriebfe825e2017-03-02 21:09:19 +0900131 result = base::MakeUnique<base::Value>(static_cast<double>(value));
dcheng6ad83f32016-05-30 15:33:58 +0900132 }
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900133 break;
134 }
135 case Message::INT64: {
avi0ad0ce02015-12-23 03:12:45 +0900136 int64_t value = 0;
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900137 if (reader->PopInt64(&value)) {
138 DLOG_IF(WARNING, !IsExactlyRepresentableByDouble(value)) <<
139 value << " is not exactly representable by double";
jdoerriebfe825e2017-03-02 21:09:19 +0900140 result = base::MakeUnique<base::Value>(static_cast<double>(value));
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900141 }
142 break;
143 }
144 case Message::UINT64: {
avi0ad0ce02015-12-23 03:12:45 +0900145 uint64_t value = 0;
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900146 if (reader->PopUint64(&value)) {
147 DLOG_IF(WARNING, !IsExactlyRepresentableByDouble(value)) <<
148 value << " is not exactly representable by double";
jdoerriebfe825e2017-03-02 21:09:19 +0900149 result = base::MakeUnique<base::Value>(static_cast<double>(value));
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900150 }
151 break;
152 }
153 case Message::DOUBLE: {
154 double value = 0;
155 if (reader->PopDouble(&value))
jdoerriebfe825e2017-03-02 21:09:19 +0900156 result = base::MakeUnique<base::Value>(value);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900157 break;
158 }
159 case Message::STRING: {
160 std::string value;
161 if (reader->PopString(&value))
jdoerrie0d1295b2017-03-06 20:12:04 +0900162 result = base::MakeUnique<base::Value>(value);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900163 break;
164 }
165 case Message::OBJECT_PATH: {
166 ObjectPath value;
167 if (reader->PopObjectPath(&value))
jdoerrie0d1295b2017-03-06 20:12:04 +0900168 result = base::MakeUnique<base::Value>(value.value());
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900169 break;
170 }
sleffler@chromium.org22fab402012-03-30 15:46:20 +0900171 case Message::UNIX_FD: {
172 // Cannot distinguish a file descriptor from an int
173 NOTREACHED();
174 break;
175 }
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900176 case Message::ARRAY: {
177 MessageReader sub_reader(NULL);
178 if (reader->PopArray(&sub_reader)) {
179 // If the type of the array's element is DICT_ENTRY, create a
180 // DictionaryValue, otherwise create a ListValue.
181 if (sub_reader.GetDataType() == Message::DICT_ENTRY) {
dcheng30c5a172016-04-09 07:55:04 +0900182 std::unique_ptr<base::DictionaryValue> dictionary_value(
thestig@chromium.orge1acdf82013-02-13 05:06:15 +0900183 new base::DictionaryValue);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900184 if (PopDictionaryEntries(&sub_reader, dictionary_value.get()))
dcheng6ad83f32016-05-30 15:33:58 +0900185 result = std::move(dictionary_value);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900186 } else {
dcheng30c5a172016-04-09 07:55:04 +0900187 std::unique_ptr<base::ListValue> list_value(new base::ListValue);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900188 if (PopListElements(&sub_reader, list_value.get()))
dcheng6ad83f32016-05-30 15:33:58 +0900189 result = std::move(list_value);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900190 }
191 }
192 break;
193 }
194 case Message::STRUCT: {
195 MessageReader sub_reader(NULL);
196 if (reader->PopStruct(&sub_reader)) {
dcheng30c5a172016-04-09 07:55:04 +0900197 std::unique_ptr<base::ListValue> list_value(new base::ListValue);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900198 if (PopListElements(&sub_reader, list_value.get()))
dcheng6ad83f32016-05-30 15:33:58 +0900199 result = std::move(list_value);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900200 }
201 break;
202 }
203 case Message::DICT_ENTRY:
204 // DICT_ENTRY must be popped as an element of an array.
205 NOTREACHED();
206 break;
207 case Message::VARIANT: {
208 MessageReader sub_reader(NULL);
209 if (reader->PopVariant(&sub_reader))
210 result = PopDataAsValue(&sub_reader);
211 break;
212 }
213 }
214 return result;
215}
216
hashimoto@chromium.orgea599822012-03-25 05:37:18 +0900217void AppendBasicTypeValueData(MessageWriter* writer, const base::Value& value) {
218 switch (value.GetType()) {
jdoerrie89ee31a2016-12-08 00:43:28 +0900219 case base::Value::Type::BOOLEAN: {
hashimoto@chromium.orgea599822012-03-25 05:37:18 +0900220 bool bool_value = false;
khorimoto@chromium.org3a567792012-03-29 04:00:06 +0900221 bool success = value.GetAsBoolean(&bool_value);
222 DCHECK(success);
hashimoto@chromium.orgea599822012-03-25 05:37:18 +0900223 writer->AppendBool(bool_value);
224 break;
225 }
jdoerrie89ee31a2016-12-08 00:43:28 +0900226 case base::Value::Type::INTEGER: {
hashimoto@chromium.orgea599822012-03-25 05:37:18 +0900227 int int_value = 0;
khorimoto@chromium.org3a567792012-03-29 04:00:06 +0900228 bool success = value.GetAsInteger(&int_value);
229 DCHECK(success);
hashimoto@chromium.orgea599822012-03-25 05:37:18 +0900230 writer->AppendInt32(int_value);
231 break;
232 }
jdoerrie89ee31a2016-12-08 00:43:28 +0900233 case base::Value::Type::DOUBLE: {
hashimoto@chromium.orgea599822012-03-25 05:37:18 +0900234 double double_value = 0;
khorimoto@chromium.org3a567792012-03-29 04:00:06 +0900235 bool success = value.GetAsDouble(&double_value);
236 DCHECK(success);
hashimoto@chromium.orgea599822012-03-25 05:37:18 +0900237 writer->AppendDouble(double_value);
238 break;
239 }
jdoerrie89ee31a2016-12-08 00:43:28 +0900240 case base::Value::Type::STRING: {
hashimoto@chromium.orgea599822012-03-25 05:37:18 +0900241 std::string string_value;
khorimoto@chromium.org3a567792012-03-29 04:00:06 +0900242 bool success = value.GetAsString(&string_value);
243 DCHECK(success);
hashimoto@chromium.orgea599822012-03-25 05:37:18 +0900244 writer->AppendString(string_value);
245 break;
246 }
247 default:
248 DLOG(ERROR) << "Unexpected type " << value.GetType();
249 break;
250 }
251}
252
253void AppendBasicTypeValueDataAsVariant(MessageWriter* writer,
254 const base::Value& value) {
255 MessageWriter sub_writer(NULL);
256 writer->OpenVariant(GetTypeSignature(value), &sub_writer);
257 AppendBasicTypeValueData(&sub_writer, value);
258 writer->CloseContainer(&sub_writer);
259}
260
armansito@chromium.org39d51b92014-05-22 20:52:55 +0900261void AppendValueData(MessageWriter* writer, const base::Value& value) {
262 switch (value.GetType()) {
jdoerrie89ee31a2016-12-08 00:43:28 +0900263 case base::Value::Type::DICTIONARY: {
armansito@chromium.org39d51b92014-05-22 20:52:55 +0900264 const base::DictionaryValue* dictionary = NULL;
265 value.GetAsDictionary(&dictionary);
266 dbus::MessageWriter array_writer(NULL);
267 writer->OpenArray("{sv}", &array_writer);
268 for (base::DictionaryValue::Iterator iter(*dictionary);
269 !iter.IsAtEnd(); iter.Advance()) {
270 dbus::MessageWriter dict_entry_writer(NULL);
271 array_writer.OpenDictEntry(&dict_entry_writer);
272 dict_entry_writer.AppendString(iter.key());
273 AppendValueDataAsVariant(&dict_entry_writer, iter.value());
274 array_writer.CloseContainer(&dict_entry_writer);
275 }
276 writer->CloseContainer(&array_writer);
277 break;
278 }
jdoerrie89ee31a2016-12-08 00:43:28 +0900279 case base::Value::Type::LIST: {
armansito@chromium.org39d51b92014-05-22 20:52:55 +0900280 const base::ListValue* list = NULL;
281 value.GetAsList(&list);
282 dbus::MessageWriter array_writer(NULL);
283 writer->OpenArray("v", &array_writer);
dcheng1fa44fb2016-05-26 03:30:47 +0900284 for (const auto& value : *list) {
jdoerrie0143ef02017-04-11 23:20:20 +0900285 AppendValueDataAsVariant(&array_writer, value);
armansito@chromium.org39d51b92014-05-22 20:52:55 +0900286 }
287 writer->CloseContainer(&array_writer);
288 break;
289 }
jdoerrie89ee31a2016-12-08 00:43:28 +0900290 case base::Value::Type::BOOLEAN:
291 case base::Value::Type::INTEGER:
292 case base::Value::Type::DOUBLE:
293 case base::Value::Type::STRING:
armansito@chromium.org39d51b92014-05-22 20:52:55 +0900294 AppendBasicTypeValueData(writer, value);
295 break;
296 default:
297 DLOG(ERROR) << "Unexpected type: " << value.GetType();
298 }
299}
300
301void AppendValueDataAsVariant(MessageWriter* writer, const base::Value& value) {
302 MessageWriter variant_writer(NULL);
303 writer->OpenVariant(GetTypeSignature(value), &variant_writer);
304 AppendValueData(&variant_writer, value);
305 writer->CloseContainer(&variant_writer);
306}
307
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900308} // namespace dbus