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