• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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