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 <memory>
8 #include <utility>
9 
10 #include "base/json/json_writer.h"
11 #include "base/logging.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(nullptr);
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.type()) {
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.type();
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 = std::make_unique<base::Value>(value);
102       break;
103     }
104     case Message::BOOL: {
105       bool value = false;
106       if (reader->PopBool(&value))
107         result = std::make_unique<base::Value>(value);
108       break;
109     }
110     case Message::INT16: {
111       int16_t value = 0;
112       if (reader->PopInt16(&value))
113         result = std::make_unique<base::Value>(value);
114       break;
115     }
116     case Message::UINT16: {
117       uint16_t value = 0;
118       if (reader->PopUint16(&value))
119         result = std::make_unique<base::Value>(value);
120       break;
121     }
122     case Message::INT32: {
123       int32_t value = 0;
124       if (reader->PopInt32(&value))
125         result = std::make_unique<base::Value>(value);
126       break;
127     }
128     case Message::UINT32: {
129       uint32_t value = 0;
130       if (reader->PopUint32(&value)) {
131         result = std::make_unique<base::Value>(static_cast<double>(value));
132       }
133       break;
134     }
135     case Message::INT64: {
136       int64_t value = 0;
137       if (reader->PopInt64(&value)) {
138         DLOG_IF(WARNING, !IsExactlyRepresentableByDouble(value)) <<
139             value << " is not exactly representable by double";
140         result = std::make_unique<base::Value>(static_cast<double>(value));
141       }
142       break;
143     }
144     case Message::UINT64: {
145       uint64_t value = 0;
146       if (reader->PopUint64(&value)) {
147         DLOG_IF(WARNING, !IsExactlyRepresentableByDouble(value)) <<
148             value << " is not exactly representable by double";
149         result = std::make_unique<base::Value>(static_cast<double>(value));
150       }
151       break;
152     }
153     case Message::DOUBLE: {
154       double value = 0;
155       if (reader->PopDouble(&value))
156         result = std::make_unique<base::Value>(value);
157       break;
158     }
159     case Message::STRING: {
160       std::string value;
161       if (reader->PopString(&value))
162         result = std::make_unique<base::Value>(value);
163       break;
164     }
165     case Message::OBJECT_PATH: {
166       ObjectPath value;
167       if (reader->PopObjectPath(&value))
168         result = std::make_unique<base::Value>(value.value());
169       break;
170     }
171     case Message::UNIX_FD: {
172       // Cannot distinguish a file descriptor from an int
173       NOTREACHED();
174       break;
175     }
176     case Message::ARRAY: {
177       MessageReader sub_reader(nullptr);
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) {
182           std::unique_ptr<base::DictionaryValue> dictionary_value(
183               new base::DictionaryValue);
184           if (PopDictionaryEntries(&sub_reader, dictionary_value.get()))
185             result = std::move(dictionary_value);
186         } else {
187           std::unique_ptr<base::ListValue> list_value(new base::ListValue);
188           if (PopListElements(&sub_reader, list_value.get()))
189             result = std::move(list_value);
190         }
191       }
192       break;
193     }
194     case Message::STRUCT: {
195       MessageReader sub_reader(nullptr);
196       if (reader->PopStruct(&sub_reader)) {
197         std::unique_ptr<base::ListValue> list_value(new base::ListValue);
198         if (PopListElements(&sub_reader, list_value.get()))
199           result = std::move(list_value);
200       }
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(nullptr);
209       if (reader->PopVariant(&sub_reader))
210         result = PopDataAsValue(&sub_reader);
211       break;
212     }
213   }
214   return result;
215 }
216 
AppendBasicTypeValueData(MessageWriter * writer,const base::Value & value)217 void AppendBasicTypeValueData(MessageWriter* writer, const base::Value& value) {
218   switch (value.type()) {
219     case base::Value::Type::BOOLEAN: {
220       bool bool_value = false;
221       bool success = value.GetAsBoolean(&bool_value);
222       DCHECK(success);
223       writer->AppendBool(bool_value);
224       break;
225     }
226     case base::Value::Type::INTEGER: {
227       int int_value = 0;
228       bool success = value.GetAsInteger(&int_value);
229       DCHECK(success);
230       writer->AppendInt32(int_value);
231       break;
232     }
233     case base::Value::Type::DOUBLE: {
234       double double_value = 0;
235       bool success = value.GetAsDouble(&double_value);
236       DCHECK(success);
237       writer->AppendDouble(double_value);
238       break;
239     }
240     case base::Value::Type::STRING: {
241       std::string string_value;
242       bool success = value.GetAsString(&string_value);
243       DCHECK(success);
244       writer->AppendString(string_value);
245       break;
246     }
247     default:
248       DLOG(ERROR) << "Unexpected type " << value.type();
249       break;
250   }
251 }
252 
AppendBasicTypeValueDataAsVariant(MessageWriter * writer,const base::Value & value)253 void AppendBasicTypeValueDataAsVariant(MessageWriter* writer,
254                                        const base::Value& value) {
255   MessageWriter sub_writer(nullptr);
256   writer->OpenVariant(GetTypeSignature(value), &sub_writer);
257   AppendBasicTypeValueData(&sub_writer, value);
258   writer->CloseContainer(&sub_writer);
259 }
260 
AppendValueData(MessageWriter * writer,const base::Value & value)261 void AppendValueData(MessageWriter* writer, const base::Value& value) {
262   switch (value.type()) {
263     case base::Value::Type::DICTIONARY: {
264       const base::DictionaryValue* dictionary = nullptr;
265       value.GetAsDictionary(&dictionary);
266       dbus::MessageWriter array_writer(nullptr);
267       writer->OpenArray("{sv}", &array_writer);
268       for (base::DictionaryValue::Iterator iter(*dictionary);
269            !iter.IsAtEnd(); iter.Advance()) {
270         dbus::MessageWriter dict_entry_writer(nullptr);
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     }
279     case base::Value::Type::LIST: {
280       const base::ListValue* list = nullptr;
281       value.GetAsList(&list);
282       dbus::MessageWriter array_writer(nullptr);
283       writer->OpenArray("v", &array_writer);
284       for (const auto& value : *list) {
285         AppendValueDataAsVariant(&array_writer, value);
286       }
287       writer->CloseContainer(&array_writer);
288       break;
289     }
290     case base::Value::Type::BOOLEAN:
291     case base::Value::Type::INTEGER:
292     case base::Value::Type::DOUBLE:
293     case base::Value::Type::STRING:
294       AppendBasicTypeValueData(writer, value);
295       break;
296     default:
297       DLOG(ERROR) << "Unexpected type: " << value.type();
298   }
299 }
300 
AppendValueDataAsVariant(MessageWriter * writer,const base::Value & value)301 void AppendValueDataAsVariant(MessageWriter* writer, const base::Value& value) {
302   MessageWriter variant_writer(nullptr);
303   writer->OpenVariant(GetTypeSignature(value), &variant_writer);
304   AppendValueData(&variant_writer, value);
305   writer->CloseContainer(&variant_writer);
306 }
307 
308 }  // namespace dbus
309