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
.get(), &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
:
81 DLOG(ERROR
) << "Unexpected type " << value
.GetType();
88 base::Value
* PopDataAsValue(MessageReader
* reader
) {
89 base::Value
* result
= NULL
;
90 switch (reader
->GetDataType()) {
91 case Message::INVALID_DATA
:
96 if (reader
->PopByte(&value
))
97 result
= new base::FundamentalValue(value
);
100 case Message::BOOL
: {
102 if (reader
->PopBool(&value
))
103 result
= new base::FundamentalValue(value
);
106 case Message::INT16
: {
108 if (reader
->PopInt16(&value
))
109 result
= new base::FundamentalValue(value
);
112 case Message::UINT16
: {
114 if (reader
->PopUint16(&value
))
115 result
= new base::FundamentalValue(value
);
118 case Message::INT32
: {
120 if (reader
->PopInt32(&value
))
121 result
= new base::FundamentalValue(value
);
124 case Message::UINT32
: {
126 if (reader
->PopUint32(&value
))
127 result
= new base::FundamentalValue(static_cast<double>(value
));
130 case Message::INT64
: {
132 if (reader
->PopInt64(&value
)) {
133 DLOG_IF(WARNING
, !IsExactlyRepresentableByDouble(value
)) <<
134 value
<< " is not exactly representable by double";
135 result
= new base::FundamentalValue(static_cast<double>(value
));
139 case Message::UINT64
: {
141 if (reader
->PopUint64(&value
)) {
142 DLOG_IF(WARNING
, !IsExactlyRepresentableByDouble(value
)) <<
143 value
<< " is not exactly representable by double";
144 result
= new base::FundamentalValue(static_cast<double>(value
));
148 case Message::DOUBLE
: {
150 if (reader
->PopDouble(&value
))
151 result
= new base::FundamentalValue(value
);
154 case Message::STRING
: {
156 if (reader
->PopString(&value
))
157 result
= new base::StringValue(value
);
160 case Message::OBJECT_PATH
: {
162 if (reader
->PopObjectPath(&value
))
163 result
= new base::StringValue(value
.value());
166 case Message::UNIX_FD
: {
167 // Cannot distinguish a file descriptor from an int
171 case Message::ARRAY
: {
172 MessageReader
sub_reader(NULL
);
173 if (reader
->PopArray(&sub_reader
)) {
174 // If the type of the array's element is DICT_ENTRY, create a
175 // DictionaryValue, otherwise create a ListValue.
176 if (sub_reader
.GetDataType() == Message::DICT_ENTRY
) {
177 scoped_ptr
<base::DictionaryValue
> dictionary_value(
178 new base::DictionaryValue
);
179 if (PopDictionaryEntries(&sub_reader
, dictionary_value
.get()))
180 result
= dictionary_value
.release();
182 scoped_ptr
<base::ListValue
> list_value(new base::ListValue
);
183 if (PopListElements(&sub_reader
, list_value
.get()))
184 result
= list_value
.release();
189 case Message::STRUCT
: {
190 MessageReader
sub_reader(NULL
);
191 if (reader
->PopStruct(&sub_reader
)) {
192 scoped_ptr
<base::ListValue
> list_value(new base::ListValue
);
193 if (PopListElements(&sub_reader
, list_value
.get()))
194 result
= list_value
.release();
198 case Message::DICT_ENTRY
:
199 // DICT_ENTRY must be popped as an element of an array.
202 case Message::VARIANT
: {
203 MessageReader
sub_reader(NULL
);
204 if (reader
->PopVariant(&sub_reader
))
205 result
= PopDataAsValue(&sub_reader
);
212 void AppendBasicTypeValueData(MessageWriter
* writer
, const base::Value
& value
) {
213 switch (value
.GetType()) {
214 case base::Value::TYPE_BOOLEAN
: {
215 bool bool_value
= false;
216 bool success
= value
.GetAsBoolean(&bool_value
);
218 writer
->AppendBool(bool_value
);
221 case base::Value::TYPE_INTEGER
: {
223 bool success
= value
.GetAsInteger(&int_value
);
225 writer
->AppendInt32(int_value
);
228 case base::Value::TYPE_DOUBLE
: {
229 double double_value
= 0;
230 bool success
= value
.GetAsDouble(&double_value
);
232 writer
->AppendDouble(double_value
);
235 case base::Value::TYPE_STRING
: {
236 std::string string_value
;
237 bool success
= value
.GetAsString(&string_value
);
239 writer
->AppendString(string_value
);
243 DLOG(ERROR
) << "Unexpected type " << value
.GetType();
248 void AppendBasicTypeValueDataAsVariant(MessageWriter
* writer
,
249 const base::Value
& value
) {
250 MessageWriter
sub_writer(NULL
);
251 writer
->OpenVariant(GetTypeSignature(value
), &sub_writer
);
252 AppendBasicTypeValueData(&sub_writer
, value
);
253 writer
->CloseContainer(&sub_writer
);