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