Skip to content

Commit

Permalink
Add dbus::PopDataAsValue
Browse files Browse the repository at this point in the history
BUG=chromium-os:16557
TEST=dbus_unittests --gtest_filter="ValuesUtilTest.*"


Review URL: http://codereview.chromium.org/9702094

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@127287 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
hashimoto@chromium.org committed Mar 16, 2012
1 parent 275c245 commit a5aae12
Show file tree
Hide file tree
Showing 4 changed files with 534 additions and 0 deletions.
3 changes: 3 additions & 0 deletions dbus/dbus.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
'property.cc',
'property.h',
'scoped_dbus_error.h',
'values_util.cc',
'values_util.h',
],
},
{
Expand Down Expand Up @@ -88,6 +90,7 @@
'property_unittest.cc',
'test_service.cc',
'test_service.h',
'values_util_unittest.cc',
],
'include_dirs': [
'..',
Expand Down
185 changes: 185 additions & 0 deletions dbus/values_util.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "dbus/values_util.h"

#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/values.h"
#include "dbus/message.h"

namespace dbus {

namespace {

// Returns whether |value| is exactly representable by double or not.
template<typename T>
bool IsExactlyRepresentableByDouble(T value) {
return value == static_cast<T>(static_cast<double>(value));
}

// Pops values from |reader| and appends them to |list_value|.
bool PopListElements(MessageReader* reader, ListValue* list_value) {
while (reader->HasMoreData()) {
Value* element_value = PopDataAsValue(reader);
if (!element_value)
return false;
list_value->Append(element_value);
}
return true;
}

// Pops dict-entries from |reader| and sets them to |dictionary_value|
bool PopDictionaryEntries(MessageReader* reader,
DictionaryValue* dictionary_value) {
while (reader->HasMoreData()) {
DCHECK_EQ(Message::DICT_ENTRY, reader->GetDataType());
MessageReader entry_reader(NULL);
if (!reader->PopDictEntry(&entry_reader))
return false;
// Get key as a string.
std::string key_string;
if (entry_reader.GetDataType() == Message::STRING) {
// If the type of keys is STRING, pop it directly.
if (!entry_reader.PopString(&key_string))
return false;
} else {
// If the type of keys is not STRING, convert it to string.
scoped_ptr<Value> key(PopDataAsValue(&entry_reader));
if (!key.get())
return false;
// Use JSONWriter to convert an arbitrary value to a string.
base::JSONWriter::Write(key.get(), &key_string);
}
// Get the value and set the key-value pair.
Value* value = PopDataAsValue(&entry_reader);
if (!value)
return false;
dictionary_value->Set(key_string, value);
}
return true;
}

} // namespace

Value* PopDataAsValue(MessageReader* reader) {
Value* result = NULL;
switch (reader->GetDataType()) {
case Message::INVALID_DATA:
// Do nothing.
break;
case Message::BYTE: {
uint8 value = 0;
if (reader->PopByte(&value))
result = Value::CreateIntegerValue(value);
break;
}
case Message::BOOL: {
bool value = false;
if (reader->PopBool(&value))
result = Value::CreateBooleanValue(value);
break;
}
case Message::INT16: {
int16 value = 0;
if (reader->PopInt16(&value))
result = Value::CreateIntegerValue(value);
break;
}
case Message::UINT16: {
uint16 value = 0;
if (reader->PopUint16(&value))
result = Value::CreateIntegerValue(value);
break;
}
case Message::INT32: {
int32 value = 0;
if (reader->PopInt32(&value))
result = Value::CreateIntegerValue(value);
break;
}
case Message::UINT32: {
uint32 value = 0;
if (reader->PopUint32(&value))
result = Value::CreateDoubleValue(value);
break;
}
case Message::INT64: {
int64 value = 0;
if (reader->PopInt64(&value)) {
DLOG_IF(WARNING, !IsExactlyRepresentableByDouble(value)) <<
value << " is not exactly representable by double";
result = Value::CreateDoubleValue(value);
}
break;
}
case Message::UINT64: {
uint64 value = 0;
if (reader->PopUint64(&value)) {
DLOG_IF(WARNING, !IsExactlyRepresentableByDouble(value)) <<
value << " is not exactly representable by double";
result = Value::CreateDoubleValue(value);
}
break;
}
case Message::DOUBLE: {
double value = 0;
if (reader->PopDouble(&value))
result = Value::CreateDoubleValue(value);
break;
}
case Message::STRING: {
std::string value;
if (reader->PopString(&value))
result = Value::CreateStringValue(value);
break;
}
case Message::OBJECT_PATH: {
ObjectPath value;
if (reader->PopObjectPath(&value))
result = Value::CreateStringValue(value.value());
break;
}
case Message::ARRAY: {
MessageReader sub_reader(NULL);
if (reader->PopArray(&sub_reader)) {
// If the type of the array's element is DICT_ENTRY, create a
// DictionaryValue, otherwise create a ListValue.
if (sub_reader.GetDataType() == Message::DICT_ENTRY) {
scoped_ptr<DictionaryValue> dictionary_value(new DictionaryValue);
if (PopDictionaryEntries(&sub_reader, dictionary_value.get()))
result = dictionary_value.release();
} else {
scoped_ptr<ListValue> list_value(new ListValue);
if (PopListElements(&sub_reader, list_value.get()))
result = list_value.release();
}
}
break;
}
case Message::STRUCT: {
MessageReader sub_reader(NULL);
if (reader->PopStruct(&sub_reader)) {
scoped_ptr<ListValue> list_value(new ListValue);
if (PopListElements(&sub_reader, list_value.get()))
result = list_value.release();
}
break;
}
case Message::DICT_ENTRY:
// DICT_ENTRY must be popped as an element of an array.
NOTREACHED();
break;
case Message::VARIANT: {
MessageReader sub_reader(NULL);
if (reader->PopVariant(&sub_reader))
result = PopDataAsValue(&sub_reader);
break;
}
}
return result;
}

} // namespace dbus
25 changes: 25 additions & 0 deletions dbus/values_util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef DBUS_VALUES_UTIL_H_
#define DBUS_VALUES_UTIL_H_
#pragma once

namespace base {
class Value;
}

namespace dbus {

class MessageReader;

// Pops a value from |reader| as a base::Value.
// Returns NULL if an error occurs.
// Note: Integer values larger than int32 (including uint32) are converted to
// double. Non-string diciontary keys are converted to strings.
base::Value* PopDataAsValue(MessageReader* reader);

} // namespace dbus

#endif // DBUS_VALUES_UTIL_H_
Loading

0 comments on commit a5aae12

Please sign in to comment.