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