blob: 7574f39a643d466b94fee5b437fdaf81cdd7d589 [file] [log] [blame]
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +09001// 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
13namespace dbus {
14
15namespace {
16
17// Returns whether |value| is exactly representable by double or not.
18template<typename T>
19bool 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|.
thestig@chromium.orge1acdf82013-02-13 05:06:15 +090024bool PopListElements(MessageReader* reader, base::ListValue* list_value) {
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +090025 while (reader->HasMoreData()) {
thestig@chromium.orge1acdf82013-02-13 05:06:15 +090026 base::Value* element_value = PopDataAsValue(reader);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +090027 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|
35bool PopDictionaryEntries(MessageReader* reader,
thestig@chromium.orge1acdf82013-02-13 05:06:15 +090036 base::DictionaryValue* dictionary_value) {
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +090037 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.
thestig@chromium.orge1acdf82013-02-13 05:06:15 +090050 scoped_ptr<base::Value> key(PopDataAsValue(&entry_reader));
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +090051 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.
thestig@chromium.orge1acdf82013-02-13 05:06:15 +090057 base::Value* value = PopDataAsValue(&entry_reader);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +090058 if (!value)
59 return false;
hashimoto@chromium.org9a576b02012-03-21 03:18:57 +090060 dictionary_value->SetWithoutPathExpansion(key_string, value);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +090061 }
62 return true;
63}
64
hashimoto@chromium.orgea599822012-03-25 05:37:18 +090065// Gets the D-Bus type signature for the value.
66std::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();
dcheng@chromium.org8164c2c2013-04-09 17:46:45 +090082 return std::string();
hashimoto@chromium.orgea599822012-03-25 05:37:18 +090083 }
84}
85
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +090086} // namespace
87
thestig@chromium.orge1acdf82013-02-13 05:06:15 +090088base::Value* PopDataAsValue(MessageReader* reader) {
89 base::Value* result = NULL;
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +090090 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))
thestig@chromium.orge1acdf82013-02-13 05:06:15 +090097 result = new base::FundamentalValue(value);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +090098 break;
99 }
100 case Message::BOOL: {
101 bool value = false;
102 if (reader->PopBool(&value))
thestig@chromium.orge1acdf82013-02-13 05:06:15 +0900103 result = new base::FundamentalValue(value);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900104 break;
105 }
106 case Message::INT16: {
107 int16 value = 0;
108 if (reader->PopInt16(&value))
thestig@chromium.orge1acdf82013-02-13 05:06:15 +0900109 result = new base::FundamentalValue(value);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900110 break;
111 }
112 case Message::UINT16: {
113 uint16 value = 0;
114 if (reader->PopUint16(&value))
thestig@chromium.orge1acdf82013-02-13 05:06:15 +0900115 result = new base::FundamentalValue(value);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900116 break;
117 }
118 case Message::INT32: {
119 int32 value = 0;
120 if (reader->PopInt32(&value))
thestig@chromium.orge1acdf82013-02-13 05:06:15 +0900121 result = new base::FundamentalValue(value);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900122 break;
123 }
124 case Message::UINT32: {
125 uint32 value = 0;
126 if (reader->PopUint32(&value))
thestig@chromium.orge1acdf82013-02-13 05:06:15 +0900127 result = new base::FundamentalValue(static_cast<double>(value));
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900128 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";
thestig@chromium.orge1acdf82013-02-13 05:06:15 +0900135 result = new base::FundamentalValue(static_cast<double>(value));
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900136 }
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";
thestig@chromium.orge1acdf82013-02-13 05:06:15 +0900144 result = new base::FundamentalValue(static_cast<double>(value));
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900145 }
146 break;
147 }
148 case Message::DOUBLE: {
149 double value = 0;
150 if (reader->PopDouble(&value))
thestig@chromium.orge1acdf82013-02-13 05:06:15 +0900151 result = new base::FundamentalValue(value);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900152 break;
153 }
154 case Message::STRING: {
155 std::string value;
156 if (reader->PopString(&value))
thestig@chromium.orge1acdf82013-02-13 05:06:15 +0900157 result = new base::StringValue(value);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900158 break;
159 }
160 case Message::OBJECT_PATH: {
161 ObjectPath value;
162 if (reader->PopObjectPath(&value))
thestig@chromium.orge1acdf82013-02-13 05:06:15 +0900163 result = new base::StringValue(value.value());
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900164 break;
165 }
sleffler@chromium.org22fab402012-03-30 15:46:20 +0900166 case Message::UNIX_FD: {
167 // Cannot distinguish a file descriptor from an int
168 NOTREACHED();
169 break;
170 }
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900171 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) {
thestig@chromium.orge1acdf82013-02-13 05:06:15 +0900177 scoped_ptr<base::DictionaryValue> dictionary_value(
178 new base::DictionaryValue);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900179 if (PopDictionaryEntries(&sub_reader, dictionary_value.get()))
180 result = dictionary_value.release();
181 } else {
thestig@chromium.orge1acdf82013-02-13 05:06:15 +0900182 scoped_ptr<base::ListValue> list_value(new base::ListValue);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900183 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)) {
thestig@chromium.orge1acdf82013-02-13 05:06:15 +0900192 scoped_ptr<base::ListValue> list_value(new base::ListValue);
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900193 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
hashimoto@chromium.orgea599822012-03-25 05:37:18 +0900212void AppendBasicTypeValueData(MessageWriter* writer, const base::Value& value) {
213 switch (value.GetType()) {
214 case base::Value::TYPE_BOOLEAN: {
215 bool bool_value = false;
khorimoto@chromium.org3a567792012-03-29 04:00:06 +0900216 bool success = value.GetAsBoolean(&bool_value);
217 DCHECK(success);
hashimoto@chromium.orgea599822012-03-25 05:37:18 +0900218 writer->AppendBool(bool_value);
219 break;
220 }
221 case base::Value::TYPE_INTEGER: {
222 int int_value = 0;
khorimoto@chromium.org3a567792012-03-29 04:00:06 +0900223 bool success = value.GetAsInteger(&int_value);
224 DCHECK(success);
hashimoto@chromium.orgea599822012-03-25 05:37:18 +0900225 writer->AppendInt32(int_value);
226 break;
227 }
228 case base::Value::TYPE_DOUBLE: {
229 double double_value = 0;
khorimoto@chromium.org3a567792012-03-29 04:00:06 +0900230 bool success = value.GetAsDouble(&double_value);
231 DCHECK(success);
hashimoto@chromium.orgea599822012-03-25 05:37:18 +0900232 writer->AppendDouble(double_value);
233 break;
234 }
235 case base::Value::TYPE_STRING: {
236 std::string string_value;
khorimoto@chromium.org3a567792012-03-29 04:00:06 +0900237 bool success = value.GetAsString(&string_value);
238 DCHECK(success);
hashimoto@chromium.orgea599822012-03-25 05:37:18 +0900239 writer->AppendString(string_value);
240 break;
241 }
242 default:
243 DLOG(ERROR) << "Unexpected type " << value.GetType();
244 break;
245 }
246}
247
248void 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
hashimoto@chromium.org8fb5a2b2012-03-17 08:08:42 +0900256} // namespace dbus