1 // 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
7 #include <utility>
8
9 #include "base/json/json_writer.h"
10 #include "base/logging.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/values.h"
13 #include "dbus/message.h"
14
15 namespace dbus {
16
17 namespace {
18
19 // Returns whether |value| is exactly representable by double or not.
20 template<typename T>
IsExactlyRepresentableByDouble(T value)21 bool 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|.
PopListElements(MessageReader * reader,base::ListValue * list_value)26 bool PopListElements(MessageReader* reader, base::ListValue* list_value) {
27 while (reader->HasMoreData()) {
28 std::unique_ptr<base::Value> element_value = PopDataAsValue(reader);
29 if (!element_value)
30 return false;
31 list_value->Append(std::move(element_value));
32 }
33 return true;
34 }
35
36 // Pops dict-entries from |reader| and sets them to |dictionary_value|
PopDictionaryEntries(MessageReader * reader,base::DictionaryValue * dictionary_value)37 bool PopDictionaryEntries(MessageReader* reader,
38 base::DictionaryValue* dictionary_value) {
39 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.
52 std::unique_ptr<base::Value> key(PopDataAsValue(&entry_reader));
53 if (!key)
54 return false;
55 // Use JSONWriter to convert an arbitrary value to a string.
56 base::JSONWriter::Write(*key, &key_string);
57 }
58 // Get the value and set the key-value pair.
59 std::unique_ptr<base::Value> value = PopDataAsValue(&entry_reader);
60 if (!value)
61 return false;
62 dictionary_value->SetWithoutPathExpansion(key_string, std::move(value));
63 }
64 return true;
65 }
66
67 // Gets the D-Bus type signature for the value.
GetTypeSignature(const base::Value & value)68 std::string GetTypeSignature(const base::Value& value) {
69 switch (value.GetType()) {
70 case base::Value::TYPE_BOOLEAN:
71 return "b";
72 case base::Value::TYPE_INTEGER:
73 return "i";
74 case base::Value::TYPE_DOUBLE:
75 return "d";
76 case base::Value::TYPE_STRING:
77 return "s";
78 case base::Value::TYPE_BINARY:
79 return "ay";
80 case base::Value::TYPE_DICTIONARY:
81 return "a{sv}";
82 case base::Value::TYPE_LIST:
83 return "av";
84 default:
85 DLOG(ERROR) << "Unexpected type " << value.GetType();
86 return std::string();
87 }
88 }
89
90 } // namespace
91
PopDataAsValue(MessageReader * reader)92 std::unique_ptr<base::Value> PopDataAsValue(MessageReader* reader) {
93 std::unique_ptr<base::Value> result;
94 switch (reader->GetDataType()) {
95 case Message::INVALID_DATA:
96 // Do nothing.
97 break;
98 case Message::BYTE: {
99 uint8_t value = 0;
100 if (reader->PopByte(&value))
101 result = base::MakeUnique<base::FundamentalValue>(value);
102 break;
103 }
104 case Message::BOOL: {
105 bool value = false;
106 if (reader->PopBool(&value))
107 result = base::MakeUnique<base::FundamentalValue>(value);
108 break;
109 }
110 case Message::INT16: {
111 int16_t value = 0;
112 if (reader->PopInt16(&value))
113 result = base::MakeUnique<base::FundamentalValue>(value);
114 break;
115 }
116 case Message::UINT16: {
117 uint16_t value = 0;
118 if (reader->PopUint16(&value))
119 result = base::MakeUnique<base::FundamentalValue>(value);
120 break;
121 }
122 case Message::INT32: {
123 int32_t value = 0;
124 if (reader->PopInt32(&value))
125 result = base::MakeUnique<base::FundamentalValue>(value);
126 break;
127 }
128 case Message::UINT32: {
129 uint32_t value = 0;
130 if (reader->PopUint32(&value)) {
131 result = base::MakeUnique<base::FundamentalValue>(
132 static_cast<double>(value));
133 }
134 break;
135 }
136 case Message::INT64: {
137 int64_t value = 0;
138 if (reader->PopInt64(&value)) {
139 DLOG_IF(WARNING, !IsExactlyRepresentableByDouble(value)) <<
140 value << " is not exactly representable by double";
141 result = base::MakeUnique<base::FundamentalValue>(
142 static_cast<double>(value));
143 }
144 break;
145 }
146 case Message::UINT64: {
147 uint64_t value = 0;
148 if (reader->PopUint64(&value)) {
149 DLOG_IF(WARNING, !IsExactlyRepresentableByDouble(value)) <<
150 value << " is not exactly representable by double";
151 result = base::MakeUnique<base::FundamentalValue>(
152 static_cast<double>(value));
153 }
154 break;
155 }
156 case Message::DOUBLE: {
157 double value = 0;
158 if (reader->PopDouble(&value))
159 result = base::MakeUnique<base::FundamentalValue>(value);
160 break;
161 }
162 case Message::STRING: {
163 std::string value;
164 if (reader->PopString(&value))
165 result = base::MakeUnique<base::StringValue>(value);
166 break;
167 }
168 case Message::OBJECT_PATH: {
169 ObjectPath value;
170 if (reader->PopObjectPath(&value))
171 result = base::MakeUnique<base::StringValue>(value.value());
172 break;
173 }
174 case Message::UNIX_FD: {
175 // Cannot distinguish a file descriptor from an int
176 NOTREACHED();
177 break;
178 }
179 case Message::ARRAY: {
180 MessageReader sub_reader(NULL);
181 if (reader->PopArray(&sub_reader)) {
182 // If the type of the array's element is DICT_ENTRY, create a
183 // DictionaryValue, otherwise create a ListValue.
184 if (sub_reader.GetDataType() == Message::DICT_ENTRY) {
185 std::unique_ptr<base::DictionaryValue> dictionary_value(
186 new base::DictionaryValue);
187 if (PopDictionaryEntries(&sub_reader, dictionary_value.get()))
188 result = std::move(dictionary_value);
189 } else {
190 std::unique_ptr<base::ListValue> list_value(new base::ListValue);
191 if (PopListElements(&sub_reader, list_value.get()))
192 result = std::move(list_value);
193 }
194 }
195 break;
196 }
197 case Message::STRUCT: {
198 MessageReader sub_reader(NULL);
199 if (reader->PopStruct(&sub_reader)) {
200 std::unique_ptr<base::ListValue> list_value(new base::ListValue);
201 if (PopListElements(&sub_reader, list_value.get()))
202 result = std::move(list_value);
203 }
204 break;
205 }
206 case Message::DICT_ENTRY:
207 // DICT_ENTRY must be popped as an element of an array.
208 NOTREACHED();
209 break;
210 case Message::VARIANT: {
211 MessageReader sub_reader(NULL);
212 if (reader->PopVariant(&sub_reader))
213 result = PopDataAsValue(&sub_reader);
214 break;
215 }
216 }
217 return result;
218 }
219
AppendBasicTypeValueData(MessageWriter * writer,const base::Value & value)220 void AppendBasicTypeValueData(MessageWriter* writer, const base::Value& value) {
221 switch (value.GetType()) {
222 case base::Value::TYPE_BOOLEAN: {
223 bool bool_value = false;
224 bool success = value.GetAsBoolean(&bool_value);
225 DCHECK(success);
226 writer->AppendBool(bool_value);
227 break;
228 }
229 case base::Value::TYPE_INTEGER: {
230 int int_value = 0;
231 bool success = value.GetAsInteger(&int_value);
232 DCHECK(success);
233 writer->AppendInt32(int_value);
234 break;
235 }
236 case base::Value::TYPE_DOUBLE: {
237 double double_value = 0;
238 bool success = value.GetAsDouble(&double_value);
239 DCHECK(success);
240 writer->AppendDouble(double_value);
241 break;
242 }
243 case base::Value::TYPE_STRING: {
244 std::string string_value;
245 bool success = value.GetAsString(&string_value);
246 DCHECK(success);
247 writer->AppendString(string_value);
248 break;
249 }
250 default:
251 DLOG(ERROR) << "Unexpected type " << value.GetType();
252 break;
253 }
254 }
255
AppendBasicTypeValueDataAsVariant(MessageWriter * writer,const base::Value & value)256 void AppendBasicTypeValueDataAsVariant(MessageWriter* writer,
257 const base::Value& value) {
258 MessageWriter sub_writer(NULL);
259 writer->OpenVariant(GetTypeSignature(value), &sub_writer);
260 AppendBasicTypeValueData(&sub_writer, value);
261 writer->CloseContainer(&sub_writer);
262 }
263
AppendValueData(MessageWriter * writer,const base::Value & value)264 void AppendValueData(MessageWriter* writer, const base::Value& value) {
265 switch (value.GetType()) {
266 case base::Value::TYPE_DICTIONARY: {
267 const base::DictionaryValue* dictionary = NULL;
268 value.GetAsDictionary(&dictionary);
269 dbus::MessageWriter array_writer(NULL);
270 writer->OpenArray("{sv}", &array_writer);
271 for (base::DictionaryValue::Iterator iter(*dictionary);
272 !iter.IsAtEnd(); iter.Advance()) {
273 dbus::MessageWriter dict_entry_writer(NULL);
274 array_writer.OpenDictEntry(&dict_entry_writer);
275 dict_entry_writer.AppendString(iter.key());
276 AppendValueDataAsVariant(&dict_entry_writer, iter.value());
277 array_writer.CloseContainer(&dict_entry_writer);
278 }
279 writer->CloseContainer(&array_writer);
280 break;
281 }
282 case base::Value::TYPE_LIST: {
283 const base::ListValue* list = NULL;
284 value.GetAsList(&list);
285 dbus::MessageWriter array_writer(NULL);
286 writer->OpenArray("v", &array_writer);
287 for (const auto& value : *list) {
288 AppendValueDataAsVariant(&array_writer, *value);
289 }
290 writer->CloseContainer(&array_writer);
291 break;
292 }
293 case base::Value::TYPE_BOOLEAN:
294 case base::Value::TYPE_INTEGER:
295 case base::Value::TYPE_DOUBLE:
296 case base::Value::TYPE_STRING:
297 AppendBasicTypeValueData(writer, value);
298 break;
299 default:
300 DLOG(ERROR) << "Unexpected type: " << value.GetType();
301 }
302 }
303
AppendValueDataAsVariant(MessageWriter * writer,const base::Value & value)304 void AppendValueDataAsVariant(MessageWriter* writer, const base::Value& value) {
305 MessageWriter variant_writer(NULL);
306 writer->OpenVariant(GetTypeSignature(value), &variant_writer);
307 AppendValueData(&variant_writer, value);
308 writer->CloseContainer(&variant_writer);
309 }
310
311 } // namespace dbus
312