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