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 <memory> 8 #include <utility> 9 10 #include "base/json/json_writer.h" 11 #include "base/logging.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> 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|. 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| 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(nullptr); 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. 68 std::string GetTypeSignature(const base::Value& value) { 69 switch (value.type()) { 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.type(); 86 return std::string(); 87 } 88 } 89 90 } // namespace 91 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 = std::make_unique<base::Value>(value); 102 break; 103 } 104 case Message::BOOL: { 105 bool value = false; 106 if (reader->PopBool(&value)) 107 result = std::make_unique<base::Value>(value); 108 break; 109 } 110 case Message::INT16: { 111 int16_t value = 0; 112 if (reader->PopInt16(&value)) 113 result = std::make_unique<base::Value>(value); 114 break; 115 } 116 case Message::UINT16: { 117 uint16_t value = 0; 118 if (reader->PopUint16(&value)) 119 result = std::make_unique<base::Value>(value); 120 break; 121 } 122 case Message::INT32: { 123 int32_t value = 0; 124 if (reader->PopInt32(&value)) 125 result = std::make_unique<base::Value>(value); 126 break; 127 } 128 case Message::UINT32: { 129 uint32_t value = 0; 130 if (reader->PopUint32(&value)) { 131 result = std::make_unique<base::Value>(static_cast<double>(value)); 132 } 133 break; 134 } 135 case Message::INT64: { 136 int64_t value = 0; 137 if (reader->PopInt64(&value)) { 138 DLOG_IF(WARNING, !IsExactlyRepresentableByDouble(value)) << 139 value << " is not exactly representable by double"; 140 result = std::make_unique<base::Value>(static_cast<double>(value)); 141 } 142 break; 143 } 144 case Message::UINT64: { 145 uint64_t value = 0; 146 if (reader->PopUint64(&value)) { 147 DLOG_IF(WARNING, !IsExactlyRepresentableByDouble(value)) << 148 value << " is not exactly representable by double"; 149 result = std::make_unique<base::Value>(static_cast<double>(value)); 150 } 151 break; 152 } 153 case Message::DOUBLE: { 154 double value = 0; 155 if (reader->PopDouble(&value)) 156 result = std::make_unique<base::Value>(value); 157 break; 158 } 159 case Message::STRING: { 160 std::string value; 161 if (reader->PopString(&value)) 162 result = std::make_unique<base::Value>(value); 163 break; 164 } 165 case Message::OBJECT_PATH: { 166 ObjectPath value; 167 if (reader->PopObjectPath(&value)) 168 result = std::make_unique<base::Value>(value.value()); 169 break; 170 } 171 case Message::UNIX_FD: { 172 // Cannot distinguish a file descriptor from an int 173 NOTREACHED(); 174 break; 175 } 176 case Message::ARRAY: { 177 MessageReader sub_reader(nullptr); 178 if (reader->PopArray(&sub_reader)) { 179 // If the type of the array's element is DICT_ENTRY, create a 180 // DictionaryValue, otherwise create a ListValue. 181 if (sub_reader.GetDataType() == Message::DICT_ENTRY) { 182 std::unique_ptr<base::DictionaryValue> dictionary_value( 183 new base::DictionaryValue); 184 if (PopDictionaryEntries(&sub_reader, dictionary_value.get())) 185 result = std::move(dictionary_value); 186 } else { 187 std::unique_ptr<base::ListValue> list_value(new base::ListValue); 188 if (PopListElements(&sub_reader, list_value.get())) 189 result = std::move(list_value); 190 } 191 } 192 break; 193 } 194 case Message::STRUCT: { 195 MessageReader sub_reader(nullptr); 196 if (reader->PopStruct(&sub_reader)) { 197 std::unique_ptr<base::ListValue> list_value(new base::ListValue); 198 if (PopListElements(&sub_reader, list_value.get())) 199 result = std::move(list_value); 200 } 201 break; 202 } 203 case Message::DICT_ENTRY: 204 // DICT_ENTRY must be popped as an element of an array. 205 NOTREACHED(); 206 break; 207 case Message::VARIANT: { 208 MessageReader sub_reader(nullptr); 209 if (reader->PopVariant(&sub_reader)) 210 result = PopDataAsValue(&sub_reader); 211 break; 212 } 213 } 214 return result; 215 } 216 217 void AppendBasicTypeValueData(MessageWriter* writer, const base::Value& value) { 218 switch (value.type()) { 219 case base::Value::Type::BOOLEAN: { 220 bool bool_value = false; 221 bool success = value.GetAsBoolean(&bool_value); 222 DCHECK(success); 223 writer->AppendBool(bool_value); 224 break; 225 } 226 case base::Value::Type::INTEGER: { 227 int int_value = 0; 228 bool success = value.GetAsInteger(&int_value); 229 DCHECK(success); 230 writer->AppendInt32(int_value); 231 break; 232 } 233 case base::Value::Type::DOUBLE: { 234 double double_value = 0; 235 bool success = value.GetAsDouble(&double_value); 236 DCHECK(success); 237 writer->AppendDouble(double_value); 238 break; 239 } 240 case base::Value::Type::STRING: { 241 std::string string_value; 242 bool success = value.GetAsString(&string_value); 243 DCHECK(success); 244 writer->AppendString(string_value); 245 break; 246 } 247 default: 248 DLOG(ERROR) << "Unexpected type " << value.type(); 249 break; 250 } 251 } 252 253 void AppendBasicTypeValueDataAsVariant(MessageWriter* writer, 254 const base::Value& value) { 255 MessageWriter sub_writer(nullptr); 256 writer->OpenVariant(GetTypeSignature(value), &sub_writer); 257 AppendBasicTypeValueData(&sub_writer, value); 258 writer->CloseContainer(&sub_writer); 259 } 260 261 void AppendValueData(MessageWriter* writer, const base::Value& value) { 262 switch (value.type()) { 263 case base::Value::Type::DICTIONARY: { 264 const base::DictionaryValue* dictionary = nullptr; 265 value.GetAsDictionary(&dictionary); 266 dbus::MessageWriter array_writer(nullptr); 267 writer->OpenArray("{sv}", &array_writer); 268 for (base::DictionaryValue::Iterator iter(*dictionary); 269 !iter.IsAtEnd(); iter.Advance()) { 270 dbus::MessageWriter dict_entry_writer(nullptr); 271 array_writer.OpenDictEntry(&dict_entry_writer); 272 dict_entry_writer.AppendString(iter.key()); 273 AppendValueDataAsVariant(&dict_entry_writer, iter.value()); 274 array_writer.CloseContainer(&dict_entry_writer); 275 } 276 writer->CloseContainer(&array_writer); 277 break; 278 } 279 case base::Value::Type::LIST: { 280 const base::ListValue* list = nullptr; 281 value.GetAsList(&list); 282 dbus::MessageWriter array_writer(nullptr); 283 writer->OpenArray("v", &array_writer); 284 for (const auto& value : *list) { 285 AppendValueDataAsVariant(&array_writer, value); 286 } 287 writer->CloseContainer(&array_writer); 288 break; 289 } 290 case base::Value::Type::BOOLEAN: 291 case base::Value::Type::INTEGER: 292 case base::Value::Type::DOUBLE: 293 case base::Value::Type::STRING: 294 AppendBasicTypeValueData(writer, value); 295 break; 296 default: 297 DLOG(ERROR) << "Unexpected type: " << value.type(); 298 } 299 } 300 301 void AppendValueDataAsVariant(MessageWriter* writer, const base::Value& value) { 302 MessageWriter variant_writer(nullptr); 303 writer->OpenVariant(GetTypeSignature(value), &variant_writer); 304 AppendValueData(&variant_writer, value); 305 writer->CloseContainer(&variant_writer); 306 } 307 308 } // namespace dbus 309