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> 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(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. 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 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 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 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 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 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