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 default: 81 DLOG(ERROR) << "Unexpected type " << value.GetType(); 82 return std::string(); 83 } 84 } 85 86 } // namespace 87 88 base::Value* PopDataAsValue(MessageReader* reader) { 89 base::Value* result = NULL; 90 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)) 97 result = new base::FundamentalValue(value); 98 break; 99 } 100 case Message::BOOL: { 101 bool value = false; 102 if (reader->PopBool(&value)) 103 result = new base::FundamentalValue(value); 104 break; 105 } 106 case Message::INT16: { 107 int16 value = 0; 108 if (reader->PopInt16(&value)) 109 result = new base::FundamentalValue(value); 110 break; 111 } 112 case Message::UINT16: { 113 uint16 value = 0; 114 if (reader->PopUint16(&value)) 115 result = new base::FundamentalValue(value); 116 break; 117 } 118 case Message::INT32: { 119 int32 value = 0; 120 if (reader->PopInt32(&value)) 121 result = new base::FundamentalValue(value); 122 break; 123 } 124 case Message::UINT32: { 125 uint32 value = 0; 126 if (reader->PopUint32(&value)) 127 result = new base::FundamentalValue(static_cast<double>(value)); 128 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"; 135 result = new base::FundamentalValue(static_cast<double>(value)); 136 } 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"; 144 result = new base::FundamentalValue(static_cast<double>(value)); 145 } 146 break; 147 } 148 case Message::DOUBLE: { 149 double value = 0; 150 if (reader->PopDouble(&value)) 151 result = new base::FundamentalValue(value); 152 break; 153 } 154 case Message::STRING: { 155 std::string value; 156 if (reader->PopString(&value)) 157 result = new base::StringValue(value); 158 break; 159 } 160 case Message::OBJECT_PATH: { 161 ObjectPath value; 162 if (reader->PopObjectPath(&value)) 163 result = new base::StringValue(value.value()); 164 break; 165 } 166 case Message::UNIX_FD: { 167 // Cannot distinguish a file descriptor from an int 168 NOTREACHED(); 169 break; 170 } 171 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) { 177 scoped_ptr<base::DictionaryValue> dictionary_value( 178 new base::DictionaryValue); 179 if (PopDictionaryEntries(&sub_reader, dictionary_value.get())) 180 result = dictionary_value.release(); 181 } else { 182 scoped_ptr<base::ListValue> list_value(new base::ListValue); 183 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)) { 192 scoped_ptr<base::ListValue> list_value(new base::ListValue); 193 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 212 void AppendBasicTypeValueData(MessageWriter* writer, const base::Value& value) { 213 switch (value.GetType()) { 214 case base::Value::TYPE_BOOLEAN: { 215 bool bool_value = false; 216 bool success = value.GetAsBoolean(&bool_value); 217 DCHECK(success); 218 writer->AppendBool(bool_value); 219 break; 220 } 221 case base::Value::TYPE_INTEGER: { 222 int int_value = 0; 223 bool success = value.GetAsInteger(&int_value); 224 DCHECK(success); 225 writer->AppendInt32(int_value); 226 break; 227 } 228 case base::Value::TYPE_DOUBLE: { 229 double double_value = 0; 230 bool success = value.GetAsDouble(&double_value); 231 DCHECK(success); 232 writer->AppendDouble(double_value); 233 break; 234 } 235 case base::Value::TYPE_STRING: { 236 std::string string_value; 237 bool success = value.GetAsString(&string_value); 238 DCHECK(success); 239 writer->AppendString(string_value); 240 break; 241 } 242 default: 243 DLOG(ERROR) << "Unexpected type " << value.GetType(); 244 break; 245 } 246 } 247 248 void 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 256 } // namespace dbus 257