Home | History | Annotate | Download | only in dbus
      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