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
, ListValue
* list_value
) {
25 while (reader
->HasMoreData()) {
26 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 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
<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 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 Value
* PopDataAsValue(MessageReader
* reader
) {
90 switch (reader
->GetDataType()) {
91 case Message::INVALID_DATA
:
96 if (reader
->PopByte(&value
))
97 result
= Value::CreateIntegerValue(value
);
100 case Message::BOOL
: {
102 if (reader
->PopBool(&value
))
103 result
= Value::CreateBooleanValue(value
);
106 case Message::INT16
: {
108 if (reader
->PopInt16(&value
))
109 result
= Value::CreateIntegerValue(value
);
112 case Message::UINT16
: {
114 if (reader
->PopUint16(&value
))
115 result
= Value::CreateIntegerValue(value
);
118 case Message::INT32
: {
120 if (reader
->PopInt32(&value
))
121 result
= Value::CreateIntegerValue(value
);
124 case Message::UINT32
: {
126 if (reader
->PopUint32(&value
))
127 result
= Value::CreateDoubleValue(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
= Value::CreateDoubleValue(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
= Value::CreateDoubleValue(value
);
148 case Message::DOUBLE
: {
150 if (reader
->PopDouble(&value
))
151 result
= Value::CreateDoubleValue(value
);
154 case Message::STRING
: {
156 if (reader
->PopString(&value
))
157 result
= Value::CreateStringValue(value
);
160 case Message::OBJECT_PATH
: {
162 if (reader
->PopObjectPath(&value
))
163 result
= Value::CreateStringValue(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
<DictionaryValue
> dictionary_value(new DictionaryValue
);
178 if (PopDictionaryEntries(&sub_reader
, dictionary_value
.get()))
179 result
= dictionary_value
.release();
181 scoped_ptr
<ListValue
> list_value(new ListValue
);
182 if (PopListElements(&sub_reader
, list_value
.get()))
183 result
= list_value
.release();
188 case Message::STRUCT
: {
189 MessageReader
sub_reader(NULL
);
190 if (reader
->PopStruct(&sub_reader
)) {
191 scoped_ptr
<ListValue
> list_value(new ListValue
);
192 if (PopListElements(&sub_reader
, list_value
.get()))
193 result
= list_value
.release();
197 case Message::DICT_ENTRY
:
198 // DICT_ENTRY must be popped as an element of an array.
201 case Message::VARIANT
: {
202 MessageReader
sub_reader(NULL
);
203 if (reader
->PopVariant(&sub_reader
))
204 result
= PopDataAsValue(&sub_reader
);
211 void AppendBasicTypeValueData(MessageWriter
* writer
, const base::Value
& value
) {
212 switch (value
.GetType()) {
213 case base::Value::TYPE_BOOLEAN
: {
214 bool bool_value
= false;
215 bool success
= value
.GetAsBoolean(&bool_value
);
217 writer
->AppendBool(bool_value
);
220 case base::Value::TYPE_INTEGER
: {
222 bool success
= value
.GetAsInteger(&int_value
);
224 writer
->AppendInt32(int_value
);
227 case base::Value::TYPE_DOUBLE
: {
228 double double_value
= 0;
229 bool success
= value
.GetAsDouble(&double_value
);
231 writer
->AppendDouble(double_value
);
234 case base::Value::TYPE_STRING
: {
235 std::string string_value
;
236 bool success
= value
.GetAsString(&string_value
);
238 writer
->AppendString(string_value
);
242 DLOG(ERROR
) << "Unexpected type " << value
.GetType();
247 void AppendBasicTypeValueDataAsVariant(MessageWriter
* writer
,
248 const base::Value
& value
) {
249 MessageWriter
sub_writer(NULL
);
250 writer
->OpenVariant(GetTypeSignature(value
), &sub_writer
);
251 AppendBasicTypeValueData(&sub_writer
, value
);
252 writer
->CloseContainer(&sub_writer
);