• 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     default:
81       DLOG(ERROR) << "Unexpected type " << value.GetType();
82       return std::string();
83   }
84 }
85 
86 }  // namespace
87 
PopDataAsValue(MessageReader * reader)88 base::Value* PopDataAsValue(MessageReader* reader) {
89   base::Value* result = NULL;
90   switch (reader->GetDataType()) {
91     case Message::INVALID_DATA:
92       // Do nothing.
93       break;
94     case Message::BYTE: {
95       uint8 value = 0;
96       if (reader->PopByte(&value))
97         result = new base::FundamentalValue(value);
98       break;
99     }
100     case Message::BOOL: {
101       bool value = false;
102       if (reader->PopBool(&value))
103         result = new base::FundamentalValue(value);
104       break;
105     }
106     case Message::INT16: {
107       int16 value = 0;
108       if (reader->PopInt16(&value))
109         result = new base::FundamentalValue(value);
110       break;
111     }
112     case Message::UINT16: {
113       uint16 value = 0;
114       if (reader->PopUint16(&value))
115         result = new base::FundamentalValue(value);
116       break;
117     }
118     case Message::INT32: {
119       int32 value = 0;
120       if (reader->PopInt32(&value))
121         result = new base::FundamentalValue(value);
122       break;
123     }
124     case Message::UINT32: {
125       uint32 value = 0;
126       if (reader->PopUint32(&value))
127         result = new base::FundamentalValue(static_cast<double>(value));
128       break;
129     }
130     case Message::INT64: {
131       int64 value = 0;
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));
136       }
137       break;
138     }
139     case Message::UINT64: {
140       uint64 value = 0;
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));
145       }
146       break;
147     }
148     case Message::DOUBLE: {
149       double value = 0;
150       if (reader->PopDouble(&value))
151         result = new base::FundamentalValue(value);
152       break;
153     }
154     case Message::STRING: {
155       std::string value;
156       if (reader->PopString(&value))
157         result = new base::StringValue(value);
158       break;
159     }
160     case Message::OBJECT_PATH: {
161       ObjectPath value;
162       if (reader->PopObjectPath(&value))
163         result = new base::StringValue(value.value());
164       break;
165     }
166     case Message::UNIX_FD: {
167       // Cannot distinguish a file descriptor from an int
168       NOTREACHED();
169       break;
170     }
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();
181         } else {
182           scoped_ptr<base::ListValue> list_value(new base::ListValue);
183           if (PopListElements(&sub_reader, list_value.get()))
184             result = list_value.release();
185         }
186       }
187       break;
188     }
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();
195       }
196       break;
197     }
198     case Message::DICT_ENTRY:
199       // DICT_ENTRY must be popped as an element of an array.
200       NOTREACHED();
201       break;
202     case Message::VARIANT: {
203       MessageReader sub_reader(NULL);
204       if (reader->PopVariant(&sub_reader))
205         result = PopDataAsValue(&sub_reader);
206       break;
207     }
208   }
209   return result;
210 }
211 
AppendBasicTypeValueData(MessageWriter * writer,const base::Value & value)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);
217       DCHECK(success);
218       writer->AppendBool(bool_value);
219       break;
220     }
221     case base::Value::TYPE_INTEGER: {
222       int int_value = 0;
223       bool success = value.GetAsInteger(&int_value);
224       DCHECK(success);
225       writer->AppendInt32(int_value);
226       break;
227     }
228     case base::Value::TYPE_DOUBLE: {
229       double double_value = 0;
230       bool success = value.GetAsDouble(&double_value);
231       DCHECK(success);
232       writer->AppendDouble(double_value);
233       break;
234     }
235     case base::Value::TYPE_STRING: {
236       std::string string_value;
237       bool success = value.GetAsString(&string_value);
238       DCHECK(success);
239       writer->AppendString(string_value);
240       break;
241     }
242     default:
243       DLOG(ERROR) << "Unexpected type " << value.GetType();
244       break;
245   }
246 }
247 
AppendBasicTypeValueDataAsVariant(MessageWriter * writer,const base::Value & value)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);
254 }
255 
256 }  // namespace dbus
257