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.
5 #include "dbus/values_util.h"
7 #include "base/json/json_writer.h"
8 #include "base/logging.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/values.h"
11 #include "dbus/message.h"
17 // Returns whether |value| is exactly representable by double or not.
19 bool IsExactlyRepresentableByDouble(T value
) {
20 return value
== static_cast<T
>(static_cast<double>(value
));
23 // Pops values from |reader| and appends them to |list_value|.
24 bool PopListElements(MessageReader
* reader
, base::ListValue
* list_value
) {
25 while (reader
->HasMoreData()) {
26 base::Value
* element_value
= PopDataAsValue(reader
);
29 list_value
->Append(element_value
);
34 // Pops dict-entries from |reader| and sets them to |dictionary_value|
35 bool PopDictionaryEntries(MessageReader
* reader
,
36 base::DictionaryValue
* dictionary_value
) {
37 while (reader
->HasMoreData()) {
38 DCHECK_EQ(Message::DICT_ENTRY
, reader
->GetDataType());
39 MessageReader
entry_reader(NULL
);
40 if (!reader
->PopDictEntry(&entry_reader
))
42 // Get key as a string.
43 std::string key_string
;
44 if (entry_reader
.GetDataType() == Message::STRING
) {
45 // If the type of keys is STRING, pop it directly.
46 if (!entry_reader
.PopString(&key_string
))
49 // If the type of keys is not STRING, convert it to string.
50 scoped_ptr
<base::Value
> key(PopDataAsValue(&entry_reader
));
53 // Use JSONWriter to convert an arbitrary value to a string.
54 base::JSONWriter::Write(*key
, &key_string
);
56 // Get the value and set the key-value pair.
57 base::Value
* value
= PopDataAsValue(&entry_reader
);
60 dictionary_value
->SetWithoutPathExpansion(key_string
, value
);
65 // Gets the D-Bus type signature for the value.
66 std::string
GetTypeSignature(const base::Value
& value
) {
67 switch (value
.GetType()) {
68 case base::Value::TYPE_BOOLEAN
:
70 case base::Value::TYPE_INTEGER
:
72 case base::Value::TYPE_DOUBLE
:
74 case base::Value::TYPE_STRING
:
76 case base::Value::TYPE_BINARY
:
78 case base::Value::TYPE_DICTIONARY
:
80 case base::Value::TYPE_LIST
:
83 DLOG(ERROR
) << "Unexpected type " << value
.GetType();
90 base::Value
* PopDataAsValue(MessageReader
* reader
) {
91 base::Value
* result
= NULL
;
92 switch (reader
->GetDataType()) {
93 case Message::INVALID_DATA
:
98 if (reader
->PopByte(&value
))
99 result
= new base::FundamentalValue(value
);
102 case Message::BOOL
: {
104 if (reader
->PopBool(&value
))
105 result
= new base::FundamentalValue(value
);
108 case Message::INT16
: {
110 if (reader
->PopInt16(&value
))
111 result
= new base::FundamentalValue(value
);
114 case Message::UINT16
: {
116 if (reader
->PopUint16(&value
))
117 result
= new base::FundamentalValue(value
);
120 case Message::INT32
: {
122 if (reader
->PopInt32(&value
))
123 result
= new base::FundamentalValue(value
);
126 case Message::UINT32
: {
128 if (reader
->PopUint32(&value
))
129 result
= new base::FundamentalValue(static_cast<double>(value
));
132 case Message::INT64
: {
134 if (reader
->PopInt64(&value
)) {
135 DLOG_IF(WARNING
, !IsExactlyRepresentableByDouble(value
)) <<
136 value
<< " is not exactly representable by double";
137 result
= new base::FundamentalValue(static_cast<double>(value
));
141 case Message::UINT64
: {
143 if (reader
->PopUint64(&value
)) {
144 DLOG_IF(WARNING
, !IsExactlyRepresentableByDouble(value
)) <<
145 value
<< " is not exactly representable by double";
146 result
= new base::FundamentalValue(static_cast<double>(value
));
150 case Message::DOUBLE
: {
152 if (reader
->PopDouble(&value
))
153 result
= new base::FundamentalValue(value
);
156 case Message::STRING
: {
158 if (reader
->PopString(&value
))
159 result
= new base::StringValue(value
);
162 case Message::OBJECT_PATH
: {
164 if (reader
->PopObjectPath(&value
))
165 result
= new base::StringValue(value
.value());
168 case Message::UNIX_FD
: {
169 // Cannot distinguish a file descriptor from an int
173 case Message::ARRAY
: {
174 MessageReader
sub_reader(NULL
);
175 if (reader
->PopArray(&sub_reader
)) {
176 // If the type of the array's element is DICT_ENTRY, create a
177 // DictionaryValue, otherwise create a ListValue.
178 if (sub_reader
.GetDataType() == Message::DICT_ENTRY
) {
179 scoped_ptr
<base::DictionaryValue
> dictionary_value(
180 new base::DictionaryValue
);
181 if (PopDictionaryEntries(&sub_reader
, dictionary_value
.get()))
182 result
= dictionary_value
.release();
184 scoped_ptr
<base::ListValue
> list_value(new base::ListValue
);
185 if (PopListElements(&sub_reader
, list_value
.get()))
186 result
= list_value
.release();
191 case Message::STRUCT
: {
192 MessageReader
sub_reader(NULL
);
193 if (reader
->PopStruct(&sub_reader
)) {
194 scoped_ptr
<base::ListValue
> list_value(new base::ListValue
);
195 if (PopListElements(&sub_reader
, list_value
.get()))
196 result
= list_value
.release();
200 case Message::DICT_ENTRY
:
201 // DICT_ENTRY must be popped as an element of an array.
204 case Message::VARIANT
: {
205 MessageReader
sub_reader(NULL
);
206 if (reader
->PopVariant(&sub_reader
))
207 result
= PopDataAsValue(&sub_reader
);
214 void AppendBasicTypeValueData(MessageWriter
* writer
, const base::Value
& value
) {
215 switch (value
.GetType()) {
216 case base::Value::TYPE_BOOLEAN
: {
217 bool bool_value
= false;
218 bool success
= value
.GetAsBoolean(&bool_value
);
220 writer
->AppendBool(bool_value
);
223 case base::Value::TYPE_INTEGER
: {
225 bool success
= value
.GetAsInteger(&int_value
);
227 writer
->AppendInt32(int_value
);
230 case base::Value::TYPE_DOUBLE
: {
231 double double_value
= 0;
232 bool success
= value
.GetAsDouble(&double_value
);
234 writer
->AppendDouble(double_value
);
237 case base::Value::TYPE_STRING
: {
238 std::string string_value
;
239 bool success
= value
.GetAsString(&string_value
);
241 writer
->AppendString(string_value
);
245 DLOG(ERROR
) << "Unexpected type " << value
.GetType();
250 void AppendBasicTypeValueDataAsVariant(MessageWriter
* writer
,
251 const base::Value
& value
) {
252 MessageWriter
sub_writer(NULL
);
253 writer
->OpenVariant(GetTypeSignature(value
), &sub_writer
);
254 AppendBasicTypeValueData(&sub_writer
, value
);
255 writer
->CloseContainer(&sub_writer
);
258 void AppendValueData(MessageWriter
* writer
, const base::Value
& value
) {
259 switch (value
.GetType()) {
260 case base::Value::TYPE_DICTIONARY
: {
261 const base::DictionaryValue
* dictionary
= NULL
;
262 value
.GetAsDictionary(&dictionary
);
263 dbus::MessageWriter
array_writer(NULL
);
264 writer
->OpenArray("{sv}", &array_writer
);
265 for (base::DictionaryValue::Iterator
iter(*dictionary
);
266 !iter
.IsAtEnd(); iter
.Advance()) {
267 dbus::MessageWriter
dict_entry_writer(NULL
);
268 array_writer
.OpenDictEntry(&dict_entry_writer
);
269 dict_entry_writer
.AppendString(iter
.key());
270 AppendValueDataAsVariant(&dict_entry_writer
, iter
.value());
271 array_writer
.CloseContainer(&dict_entry_writer
);
273 writer
->CloseContainer(&array_writer
);
276 case base::Value::TYPE_LIST
: {
277 const base::ListValue
* list
= NULL
;
278 value
.GetAsList(&list
);
279 dbus::MessageWriter
array_writer(NULL
);
280 writer
->OpenArray("v", &array_writer
);
281 for (base::ListValue::const_iterator iter
= list
->begin();
282 iter
!= list
->end(); ++iter
) {
283 const base::Value
* value
= *iter
;
284 AppendValueDataAsVariant(&array_writer
, *value
);
286 writer
->CloseContainer(&array_writer
);
289 case base::Value::TYPE_BOOLEAN
:
290 case base::Value::TYPE_INTEGER
:
291 case base::Value::TYPE_DOUBLE
:
292 case base::Value::TYPE_STRING
:
293 AppendBasicTypeValueData(writer
, value
);
296 DLOG(ERROR
) << "Unexpected type: " << value
.GetType();
300 void AppendValueDataAsVariant(MessageWriter
* writer
, const base::Value
& value
) {
301 MessageWriter
variant_writer(NULL
);
302 writer
->OpenVariant(GetTypeSignature(value
), &variant_writer
);
303 AppendValueData(&variant_writer
, value
);
304 writer
->CloseContainer(&variant_writer
);