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 "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"
12
13 namespace dbus {
14
15 namespace {
16
17 // Returns whether |value| is exactly representable by double or not.
18 template<typename T>
IsExactlyRepresentableByDouble(T value)19 bool IsExactlyRepresentableByDouble(T value) {
20 return value == static_cast<T>(static_cast<double>(value));
21 }
22
23 // Pops values from |reader| and appends them to |list_value|.
PopListElements(MessageReader * reader,base::ListValue * list_value)24 bool PopListElements(MessageReader* reader, base::ListValue* list_value) {
25 while (reader->HasMoreData()) {
26 base::Value* element_value = PopDataAsValue(reader);
27 if (!element_value)
28 return false;
29 list_value->Append(element_value);
30 }
31 return true;
32 }
33
34 // Pops dict-entries from |reader| and sets them to |dictionary_value|
PopDictionaryEntries(MessageReader * reader,base::DictionaryValue * 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))
41 return false;
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))
47 return false;
48 } else {
49 // If the type of keys is not STRING, convert it to string.
50 scoped_ptr<base::Value> key(PopDataAsValue(&entry_reader));
51 if (!key.get())
52 return false;
53 // Use JSONWriter to convert an arbitrary value to a string.
54 base::JSONWriter::Write(key.get(), &key_string);
55 }
56 // Get the value and set the key-value pair.
57 base::Value* value = PopDataAsValue(&entry_reader);
58 if (!value)
59 return false;
60 dictionary_value->SetWithoutPathExpansion(key_string, value);
61 }
62 return true;
63 }
64
65 // Gets the D-Bus type signature for the value.
GetTypeSignature(const base::Value & value)66 std::string GetTypeSignature(const base::Value& value) {
67 switch (value.GetType()) {
68 case base::Value::TYPE_BOOLEAN:
69 return "b";
70 case base::Value::TYPE_INTEGER:
71 return "i";
72 case base::Value::TYPE_DOUBLE:
73 return "d";
74 case base::Value::TYPE_STRING:
75 return "s";
76 case base::Value::TYPE_BINARY:
77 return "ay";
78 case base::Value::TYPE_DICTIONARY:
79 return "a{sv}";
80 case base::Value::TYPE_LIST:
81 return "av";
82 default:
83 DLOG(ERROR) << "Unexpected type " << value.GetType();
84 return std::string();
85 }
86 }
87
88 } // namespace
89
PopDataAsValue(MessageReader * reader)90 base::Value* PopDataAsValue(MessageReader* reader) {
91 base::Value* result = NULL;
92 switch (reader->GetDataType()) {
93 case Message::INVALID_DATA:
94 // Do nothing.
95 break;
96 case Message::BYTE: {
97 uint8 value = 0;
98 if (reader->PopByte(&value))
99 result = new base::FundamentalValue(value);
100 break;
101 }
102 case Message::BOOL: {
103 bool value = false;
104 if (reader->PopBool(&value))
105 result = new base::FundamentalValue(value);
106 break;
107 }
108 case Message::INT16: {
109 int16 value = 0;
110 if (reader->PopInt16(&value))
111 result = new base::FundamentalValue(value);
112 break;
113 }
114 case Message::UINT16: {
115 uint16 value = 0;
116 if (reader->PopUint16(&value))
117 result = new base::FundamentalValue(value);
118 break;
119 }
120 case Message::INT32: {
121 int32 value = 0;
122 if (reader->PopInt32(&value))
123 result = new base::FundamentalValue(value);
124 break;
125 }
126 case Message::UINT32: {
127 uint32 value = 0;
128 if (reader->PopUint32(&value))
129 result = new base::FundamentalValue(static_cast<double>(value));
130 break;
131 }
132 case Message::INT64: {
133 int64 value = 0;
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));
138 }
139 break;
140 }
141 case Message::UINT64: {
142 uint64 value = 0;
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));
147 }
148 break;
149 }
150 case Message::DOUBLE: {
151 double value = 0;
152 if (reader->PopDouble(&value))
153 result = new base::FundamentalValue(value);
154 break;
155 }
156 case Message::STRING: {
157 std::string value;
158 if (reader->PopString(&value))
159 result = new base::StringValue(value);
160 break;
161 }
162 case Message::OBJECT_PATH: {
163 ObjectPath value;
164 if (reader->PopObjectPath(&value))
165 result = new base::StringValue(value.value());
166 break;
167 }
168 case Message::UNIX_FD: {
169 // Cannot distinguish a file descriptor from an int
170 NOTREACHED();
171 break;
172 }
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();
183 } else {
184 scoped_ptr<base::ListValue> list_value(new base::ListValue);
185 if (PopListElements(&sub_reader, list_value.get()))
186 result = list_value.release();
187 }
188 }
189 break;
190 }
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();
197 }
198 break;
199 }
200 case Message::DICT_ENTRY:
201 // DICT_ENTRY must be popped as an element of an array.
202 NOTREACHED();
203 break;
204 case Message::VARIANT: {
205 MessageReader sub_reader(NULL);
206 if (reader->PopVariant(&sub_reader))
207 result = PopDataAsValue(&sub_reader);
208 break;
209 }
210 }
211 return result;
212 }
213
AppendBasicTypeValueData(MessageWriter * writer,const base::Value & value)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);
219 DCHECK(success);
220 writer->AppendBool(bool_value);
221 break;
222 }
223 case base::Value::TYPE_INTEGER: {
224 int int_value = 0;
225 bool success = value.GetAsInteger(&int_value);
226 DCHECK(success);
227 writer->AppendInt32(int_value);
228 break;
229 }
230 case base::Value::TYPE_DOUBLE: {
231 double double_value = 0;
232 bool success = value.GetAsDouble(&double_value);
233 DCHECK(success);
234 writer->AppendDouble(double_value);
235 break;
236 }
237 case base::Value::TYPE_STRING: {
238 std::string string_value;
239 bool success = value.GetAsString(&string_value);
240 DCHECK(success);
241 writer->AppendString(string_value);
242 break;
243 }
244 default:
245 DLOG(ERROR) << "Unexpected type " << value.GetType();
246 break;
247 }
248 }
249
AppendBasicTypeValueDataAsVariant(MessageWriter * writer,const base::Value & value)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);
256 }
257
AppendValueData(MessageWriter * writer,const base::Value & value)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);
272 }
273 writer->CloseContainer(&array_writer);
274 break;
275 }
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);
285 }
286 writer->CloseContainer(&array_writer);
287 break;
288 }
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);
294 break;
295 default:
296 DLOG(ERROR) << "Unexpected type: " << value.GetType();
297 }
298 }
299
AppendValueDataAsVariant(MessageWriter * writer,const base::Value & value)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);
305 }
306
307 } // namespace dbus
308