• 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 <utility>
8 
9 #include "base/json/json_writer.h"
10 #include "base/logging.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/values.h"
13 #include "dbus/message.h"
14 
15 namespace dbus {
16 
17 namespace {
18 
19 // Returns whether |value| is exactly representable by double or not.
20 template<typename T>
IsExactlyRepresentableByDouble(T value)21 bool IsExactlyRepresentableByDouble(T value) {
22   return value == static_cast<T>(static_cast<double>(value));
23 }
24 
25 // Pops values from |reader| and appends them to |list_value|.
PopListElements(MessageReader * reader,base::ListValue * list_value)26 bool PopListElements(MessageReader* reader, base::ListValue* list_value) {
27   while (reader->HasMoreData()) {
28     std::unique_ptr<base::Value> element_value = PopDataAsValue(reader);
29     if (!element_value)
30       return false;
31     list_value->Append(std::move(element_value));
32   }
33   return true;
34 }
35 
36 // Pops dict-entries from |reader| and sets them to |dictionary_value|
PopDictionaryEntries(MessageReader * reader,base::DictionaryValue * dictionary_value)37 bool PopDictionaryEntries(MessageReader* reader,
38                           base::DictionaryValue* dictionary_value) {
39   while (reader->HasMoreData()) {
40     DCHECK_EQ(Message::DICT_ENTRY, reader->GetDataType());
41     MessageReader entry_reader(NULL);
42     if (!reader->PopDictEntry(&entry_reader))
43       return false;
44     // Get key as a string.
45     std::string key_string;
46     if (entry_reader.GetDataType() == Message::STRING) {
47       // If the type of keys is STRING, pop it directly.
48       if (!entry_reader.PopString(&key_string))
49         return false;
50     } else {
51       // If the type of keys is not STRING, convert it to string.
52       std::unique_ptr<base::Value> key(PopDataAsValue(&entry_reader));
53       if (!key)
54         return false;
55       // Use JSONWriter to convert an arbitrary value to a string.
56       base::JSONWriter::Write(*key, &key_string);
57     }
58     // Get the value and set the key-value pair.
59     std::unique_ptr<base::Value> value = PopDataAsValue(&entry_reader);
60     if (!value)
61       return false;
62     dictionary_value->SetWithoutPathExpansion(key_string, std::move(value));
63   }
64   return true;
65 }
66 
67 // Gets the D-Bus type signature for the value.
GetTypeSignature(const base::Value & value)68 std::string GetTypeSignature(const base::Value& value) {
69   switch (value.GetType()) {
70     case base::Value::TYPE_BOOLEAN:
71       return "b";
72     case base::Value::TYPE_INTEGER:
73       return "i";
74     case base::Value::TYPE_DOUBLE:
75       return "d";
76     case base::Value::TYPE_STRING:
77       return "s";
78     case base::Value::TYPE_BINARY:
79       return "ay";
80     case base::Value::TYPE_DICTIONARY:
81       return "a{sv}";
82     case base::Value::TYPE_LIST:
83       return "av";
84     default:
85       DLOG(ERROR) << "Unexpected type " << value.GetType();
86       return std::string();
87   }
88 }
89 
90 }  // namespace
91 
PopDataAsValue(MessageReader * reader)92 std::unique_ptr<base::Value> PopDataAsValue(MessageReader* reader) {
93   std::unique_ptr<base::Value> result;
94   switch (reader->GetDataType()) {
95     case Message::INVALID_DATA:
96       // Do nothing.
97       break;
98     case Message::BYTE: {
99       uint8_t value = 0;
100       if (reader->PopByte(&value))
101         result = base::MakeUnique<base::FundamentalValue>(value);
102       break;
103     }
104     case Message::BOOL: {
105       bool value = false;
106       if (reader->PopBool(&value))
107         result = base::MakeUnique<base::FundamentalValue>(value);
108       break;
109     }
110     case Message::INT16: {
111       int16_t value = 0;
112       if (reader->PopInt16(&value))
113         result = base::MakeUnique<base::FundamentalValue>(value);
114       break;
115     }
116     case Message::UINT16: {
117       uint16_t value = 0;
118       if (reader->PopUint16(&value))
119         result = base::MakeUnique<base::FundamentalValue>(value);
120       break;
121     }
122     case Message::INT32: {
123       int32_t value = 0;
124       if (reader->PopInt32(&value))
125         result = base::MakeUnique<base::FundamentalValue>(value);
126       break;
127     }
128     case Message::UINT32: {
129       uint32_t value = 0;
130       if (reader->PopUint32(&value)) {
131         result = base::MakeUnique<base::FundamentalValue>(
132             static_cast<double>(value));
133       }
134       break;
135     }
136     case Message::INT64: {
137       int64_t value = 0;
138       if (reader->PopInt64(&value)) {
139         DLOG_IF(WARNING, !IsExactlyRepresentableByDouble(value)) <<
140             value << " is not exactly representable by double";
141         result = base::MakeUnique<base::FundamentalValue>(
142             static_cast<double>(value));
143       }
144       break;
145     }
146     case Message::UINT64: {
147       uint64_t value = 0;
148       if (reader->PopUint64(&value)) {
149         DLOG_IF(WARNING, !IsExactlyRepresentableByDouble(value)) <<
150             value << " is not exactly representable by double";
151         result = base::MakeUnique<base::FundamentalValue>(
152             static_cast<double>(value));
153       }
154       break;
155     }
156     case Message::DOUBLE: {
157       double value = 0;
158       if (reader->PopDouble(&value))
159         result = base::MakeUnique<base::FundamentalValue>(value);
160       break;
161     }
162     case Message::STRING: {
163       std::string value;
164       if (reader->PopString(&value))
165         result = base::MakeUnique<base::StringValue>(value);
166       break;
167     }
168     case Message::OBJECT_PATH: {
169       ObjectPath value;
170       if (reader->PopObjectPath(&value))
171         result = base::MakeUnique<base::StringValue>(value.value());
172       break;
173     }
174     case Message::UNIX_FD: {
175       // Cannot distinguish a file descriptor from an int
176       NOTREACHED();
177       break;
178     }
179     case Message::ARRAY: {
180       MessageReader sub_reader(NULL);
181       if (reader->PopArray(&sub_reader)) {
182         // If the type of the array's element is DICT_ENTRY, create a
183         // DictionaryValue, otherwise create a ListValue.
184         if (sub_reader.GetDataType() == Message::DICT_ENTRY) {
185           std::unique_ptr<base::DictionaryValue> dictionary_value(
186               new base::DictionaryValue);
187           if (PopDictionaryEntries(&sub_reader, dictionary_value.get()))
188             result = std::move(dictionary_value);
189         } else {
190           std::unique_ptr<base::ListValue> list_value(new base::ListValue);
191           if (PopListElements(&sub_reader, list_value.get()))
192             result = std::move(list_value);
193         }
194       }
195       break;
196     }
197     case Message::STRUCT: {
198       MessageReader sub_reader(NULL);
199       if (reader->PopStruct(&sub_reader)) {
200         std::unique_ptr<base::ListValue> list_value(new base::ListValue);
201         if (PopListElements(&sub_reader, list_value.get()))
202           result = std::move(list_value);
203       }
204       break;
205     }
206     case Message::DICT_ENTRY:
207       // DICT_ENTRY must be popped as an element of an array.
208       NOTREACHED();
209       break;
210     case Message::VARIANT: {
211       MessageReader sub_reader(NULL);
212       if (reader->PopVariant(&sub_reader))
213         result = PopDataAsValue(&sub_reader);
214       break;
215     }
216   }
217   return result;
218 }
219 
AppendBasicTypeValueData(MessageWriter * writer,const base::Value & value)220 void AppendBasicTypeValueData(MessageWriter* writer, const base::Value& value) {
221   switch (value.GetType()) {
222     case base::Value::TYPE_BOOLEAN: {
223       bool bool_value = false;
224       bool success = value.GetAsBoolean(&bool_value);
225       DCHECK(success);
226       writer->AppendBool(bool_value);
227       break;
228     }
229     case base::Value::TYPE_INTEGER: {
230       int int_value = 0;
231       bool success = value.GetAsInteger(&int_value);
232       DCHECK(success);
233       writer->AppendInt32(int_value);
234       break;
235     }
236     case base::Value::TYPE_DOUBLE: {
237       double double_value = 0;
238       bool success = value.GetAsDouble(&double_value);
239       DCHECK(success);
240       writer->AppendDouble(double_value);
241       break;
242     }
243     case base::Value::TYPE_STRING: {
244       std::string string_value;
245       bool success = value.GetAsString(&string_value);
246       DCHECK(success);
247       writer->AppendString(string_value);
248       break;
249     }
250     default:
251       DLOG(ERROR) << "Unexpected type " << value.GetType();
252       break;
253   }
254 }
255 
AppendBasicTypeValueDataAsVariant(MessageWriter * writer,const base::Value & value)256 void AppendBasicTypeValueDataAsVariant(MessageWriter* writer,
257                                        const base::Value& value) {
258   MessageWriter sub_writer(NULL);
259   writer->OpenVariant(GetTypeSignature(value), &sub_writer);
260   AppendBasicTypeValueData(&sub_writer, value);
261   writer->CloseContainer(&sub_writer);
262 }
263 
AppendValueData(MessageWriter * writer,const base::Value & value)264 void AppendValueData(MessageWriter* writer, const base::Value& value) {
265   switch (value.GetType()) {
266     case base::Value::TYPE_DICTIONARY: {
267       const base::DictionaryValue* dictionary = NULL;
268       value.GetAsDictionary(&dictionary);
269       dbus::MessageWriter array_writer(NULL);
270       writer->OpenArray("{sv}", &array_writer);
271       for (base::DictionaryValue::Iterator iter(*dictionary);
272            !iter.IsAtEnd(); iter.Advance()) {
273         dbus::MessageWriter dict_entry_writer(NULL);
274         array_writer.OpenDictEntry(&dict_entry_writer);
275         dict_entry_writer.AppendString(iter.key());
276         AppendValueDataAsVariant(&dict_entry_writer, iter.value());
277         array_writer.CloseContainer(&dict_entry_writer);
278       }
279       writer->CloseContainer(&array_writer);
280       break;
281     }
282     case base::Value::TYPE_LIST: {
283       const base::ListValue* list = NULL;
284       value.GetAsList(&list);
285       dbus::MessageWriter array_writer(NULL);
286       writer->OpenArray("v", &array_writer);
287       for (const auto& value : *list) {
288         AppendValueDataAsVariant(&array_writer, *value);
289       }
290       writer->CloseContainer(&array_writer);
291       break;
292     }
293     case base::Value::TYPE_BOOLEAN:
294     case base::Value::TYPE_INTEGER:
295     case base::Value::TYPE_DOUBLE:
296     case base::Value::TYPE_STRING:
297       AppendBasicTypeValueData(writer, value);
298       break;
299     default:
300       DLOG(ERROR) << "Unexpected type: " << value.GetType();
301   }
302 }
303 
AppendValueDataAsVariant(MessageWriter * writer,const base::Value & value)304 void AppendValueDataAsVariant(MessageWriter* writer, const base::Value& value) {
305   MessageWriter variant_writer(NULL);
306   writer->OpenVariant(GetTypeSignature(value), &variant_writer);
307   AppendValueData(&variant_writer, value);
308   writer->CloseContainer(&variant_writer);
309 }
310 
311 }  // namespace dbus
312