summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormpcomplete@google.com <mpcomplete@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-21 01:01:59 +0000
committermpcomplete@google.com <mpcomplete@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-21 01:01:59 +0000
commit584f2b2101da22d458c24fdaf9ccc8112834508e (patch)
tree8e6728ce079e61cc216974c795cfb697ebce447b
parenta37ebbc3c152f9e2ff6b1e1726cf6cd2ad4da8a0 (diff)
downloadchromium_src-584f2b2101da22d458c24fdaf9ccc8112834508e.zip
chromium_src-584f2b2101da22d458c24fdaf9ccc8112834508e.tar.gz
chromium_src-584f2b2101da22d458c24fdaf9ccc8112834508e.tar.bz2
Add IPC serialization for DictionaryValue and ListValue, with unit tests.
Review URL: http://codereview.chromium.org/115491 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16562 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/common/ipc_message_unittest.cc59
-rw-r--r--chrome/common/ipc_message_utils.cc224
-rw-r--r--chrome/common/ipc_message_utils.h18
3 files changed, 300 insertions, 1 deletions
diff --git a/chrome/common/ipc_message_unittest.cc b/chrome/common/ipc_message_unittest.cc
index 2c6c48d5..332f529 100644
--- a/chrome/common/ipc_message_unittest.cc
+++ b/chrome/common/ipc_message_unittest.cc
@@ -4,9 +4,10 @@
#include <string.h>
+#include "base/scoped_ptr.h"
+#include "base/values.h"
#include "chrome/common/ipc_message.h"
#include "chrome/common/ipc_message_utils.h"
-#include "base/scoped_ptr.h"
#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -91,3 +92,59 @@ TEST(IPCMessageTest, Bitmap) {
iter = NULL;
EXPECT_FALSE(IPC::ParamTraits<SkBitmap>::Read(&bad_msg, &iter, &bad_output));
}
+
+TEST(IPCMessageTest, ListValue) {
+ ListValue input;
+ input.Set(0, Value::CreateRealValue(42.42));
+ input.Set(1, Value::CreateStringValue("forty"));
+ input.Set(2, Value::CreateNullValue());
+
+ IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+ IPC::WriteParam(&msg, input);
+
+ ListValue output;
+ void* iter = NULL;
+ EXPECT_TRUE(IPC::ReadParam(&msg, &iter, &output));
+
+ EXPECT_TRUE(input.Equals(&output));
+
+ // Also test the corrupt case.
+ IPC::Message bad_msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+ bad_msg.WriteInt(99);
+ iter = NULL;
+ EXPECT_FALSE(IPC::ReadParam(&bad_msg, &iter, &output));
+}
+
+TEST(IPCMessageTest, DictionaryValue) {
+ DictionaryValue input;
+ input.Set(L"null", Value::CreateNullValue());
+ input.Set(L"bool", Value::CreateBooleanValue(true));
+ input.Set(L"int", Value::CreateIntegerValue(42));
+
+ scoped_ptr<DictionaryValue> subdict(new DictionaryValue());
+ subdict->Set(L"str", Value::CreateStringValue("forty two"));
+ subdict->Set(L"bool", Value::CreateBooleanValue(false));
+
+ scoped_ptr<ListValue> sublist(new ListValue());
+ sublist->Set(0, Value::CreateRealValue(42.42));
+ sublist->Set(1, Value::CreateStringValue("forty"));
+ sublist->Set(2, Value::CreateStringValue("two"));
+ subdict->Set(L"list", sublist.release());
+
+ input.Set(L"dict", subdict.release());
+
+ IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+ IPC::WriteParam(&msg, input);
+
+ DictionaryValue output;
+ void* iter = NULL;
+ EXPECT_TRUE(IPC::ReadParam(&msg, &iter, &output));
+
+ EXPECT_TRUE(input.Equals(&output));
+
+ // Also test the corrupt case.
+ IPC::Message bad_msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+ bad_msg.WriteInt(99);
+ iter = NULL;
+ EXPECT_FALSE(IPC::ReadParam(&bad_msg, &iter, &output));
+}
diff --git a/chrome/common/ipc_message_utils.cc b/chrome/common/ipc_message_utils.cc
index 3b5fd76..81b9373 100644
--- a/chrome/common/ipc_message_utils.cc
+++ b/chrome/common/ipc_message_utils.cc
@@ -5,6 +5,9 @@
#include "chrome/common/ipc_message_utils.h"
#include "base/gfx/rect.h"
+#include "base/json_writer.h"
+#include "base/scoped_ptr.h"
+#include "base/values.h"
#include "googleurl/src/gurl.h"
#ifndef EXCLUDE_SKIA_DEPENDENCIES
#include "third_party/skia/include/core/SkBitmap.h"
@@ -52,6 +55,8 @@ struct SkBitmap_Data {
}
};
+const int kMaxRecursionDepth = 100;
+
} // namespace
@@ -221,4 +226,223 @@ void ParamTraits<webkit_glue::WebApplicationInfo>::Log(
l->append(L"<WebApplicationInfo>");
}
+// Value serialization
+
+static bool ReadValue(const Message* m, void** iter, Value** value,
+ int recursion);
+
+static void WriteValue(Message* m, const Value* value, int recursion) {
+ if (recursion > kMaxRecursionDepth) {
+ LOG(WARNING) << "Max recursion depth hit in WriteValue.";
+ return;
+ }
+
+ m->WriteInt(value->GetType());
+
+ switch (value->GetType()) {
+ case Value::TYPE_NULL:
+ break;
+ case Value::TYPE_BOOLEAN: {
+ bool val;
+ value->GetAsBoolean(&val);
+ WriteParam(m, val);
+ break;
+ }
+ case Value::TYPE_INTEGER: {
+ int val;
+ value->GetAsInteger(&val);
+ WriteParam(m, val);
+ break;
+ }
+ case Value::TYPE_REAL: {
+ double val;
+ value->GetAsReal(&val);
+ WriteParam(m, val);
+ break;
+ }
+ case Value::TYPE_STRING: {
+ std::string val;
+ value->GetAsString(&val);
+ WriteParam(m, val);
+ break;
+ }
+ case Value::TYPE_BINARY: {
+ NOTREACHED() << "Don't send BinaryValues over IPC.";
+ }
+ case Value::TYPE_DICTIONARY: {
+ const DictionaryValue* dict = static_cast<const DictionaryValue*>(value);
+
+ WriteParam(m, static_cast<int>(dict->GetSize()));
+
+ for (DictionaryValue::key_iterator it = dict->begin_keys();
+ it != dict->end_keys(); ++it) {
+ Value* subval;
+ if (dict->Get(*it, &subval)) {
+ WriteParam(m, *it);
+ WriteValue(m, subval, recursion + 1);
+ } else {
+ NOTREACHED() << "DictionaryValue iterators are filthy liars.";
+ }
+ }
+ break;
+ }
+ case Value::TYPE_LIST: {
+ const ListValue* list = static_cast<const ListValue*>(value);
+ WriteParam(m, static_cast<int>(list->GetSize()));
+ for (size_t i = 0; i < list->GetSize(); ++i) {
+ Value* subval;
+ if (list->Get(i, &subval)) {
+ WriteValue(m, subval, recursion + 1);
+ } else {
+ NOTREACHED() << "ListValue::GetSize is a filthy liar.";
+ }
+ }
+ break;
+ }
+ }
+}
+
+// Helper for ReadValue that reads a DictionaryValue into a pre-allocated
+// object.
+static bool ReadDictionaryValue(const Message* m, void** iter,
+ DictionaryValue* value, int recursion) {
+ int size;
+ if (!ReadParam(m, iter, &size))
+ return false;
+
+ for (int i = 0; i < size; ++i) {
+ std::wstring key;
+ Value* subval;
+ if (!ReadParam(m, iter, &key) ||
+ !ReadValue(m, iter, &subval, recursion + 1))
+ return false;
+ value->Set(key, subval);
+ }
+
+ return true;
+}
+
+// Helper for ReadValue that reads a ReadListValue into a pre-allocated
+// object.
+static bool ReadListValue(const Message* m, void** iter,
+ ListValue* value, int recursion) {
+ int size;
+ if (!ReadParam(m, iter, &size))
+ return false;
+
+ for (int i = 0; i < size; ++i) {
+ Value* subval;
+ if (!ReadValue(m, iter, &subval, recursion + 1))
+ return false;
+ value->Set(i, subval);
+ }
+
+ return true;
+}
+
+static bool ReadValue(const Message* m, void** iter, Value** value,
+ int recursion) {
+ if (recursion > kMaxRecursionDepth) {
+ LOG(WARNING) << "Max recursion depth hit in ReadValue.";
+ return false;
+ }
+
+ int type;
+ if (!ReadParam(m, iter, &type))
+ return false;
+
+ switch (type) {
+ case Value::TYPE_NULL:
+ *value = Value::CreateNullValue();
+ break;
+ case Value::TYPE_BOOLEAN: {
+ bool val;
+ if (!ReadParam(m, iter, &val))
+ return false;
+ *value = Value::CreateBooleanValue(val);
+ break;
+ }
+ case Value::TYPE_INTEGER: {
+ int val;
+ if (!ReadParam(m, iter, &val))
+ return false;
+ *value = Value::CreateIntegerValue(val);
+ break;
+ }
+ case Value::TYPE_REAL: {
+ double val;
+ if (!ReadParam(m, iter, &val))
+ return false;
+ *value = Value::CreateRealValue(val);
+ break;
+ }
+ case Value::TYPE_STRING: {
+ std::string val;
+ if (!ReadParam(m, iter, &val))
+ return false;
+ *value = Value::CreateStringValue(val);
+ break;
+ }
+ case Value::TYPE_BINARY: {
+ NOTREACHED() << "Don't send BinaryValues over IPC.";
+ break;
+ }
+ case Value::TYPE_DICTIONARY: {
+ scoped_ptr<DictionaryValue> val(new DictionaryValue());
+ if (!ReadDictionaryValue(m, iter, val.get(), recursion))
+ return false;
+ *value = val.release();
+ break;
+ }
+ case Value::TYPE_LIST: {
+ scoped_ptr<ListValue> val(new ListValue());
+ if (!ReadListValue(m, iter, val.get(), recursion))
+ return false;
+ *value = val.release();
+ break;
+ }
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+void ParamTraits<DictionaryValue>::Write(Message* m, const param_type& p) {
+ WriteValue(m, &p, 0);
+}
+
+bool ParamTraits<DictionaryValue>::Read(
+ const Message* m, void** iter, param_type* r) {
+ int type;
+ if (!ReadParam(m, iter, &type) || type != Value::TYPE_DICTIONARY)
+ return false;
+
+ return ReadDictionaryValue(m, iter, r, 0);
+}
+
+void ParamTraits<DictionaryValue>::Log(const param_type& p, std::wstring* l) {
+ std::string json;
+ JSONWriter::Write(&p, false, &json);
+ l->append(UTF8ToWide(json));
+}
+
+void ParamTraits<ListValue>::Write(Message* m, const param_type& p) {
+ WriteValue(m, &p, 0);
+}
+
+bool ParamTraits<ListValue>::Read(
+ const Message* m, void** iter, param_type* r) {
+ int type;
+ if (!ReadParam(m, iter, &type) || type != Value::TYPE_LIST)
+ return false;
+
+ return ReadListValue(m, iter, r, 0);
+}
+
+void ParamTraits<ListValue>::Log(const param_type& p, std::wstring* l) {
+ std::string json;
+ JSONWriter::Write(&p, false, &json);
+ l->append(UTF8ToWide(json));
+}
} // namespace IPC
diff --git a/chrome/common/ipc_message_utils.h b/chrome/common/ipc_message_utils.h
index cc47946..ff33e6a 100644
--- a/chrome/common/ipc_message_utils.h
+++ b/chrome/common/ipc_message_utils.h
@@ -25,6 +25,8 @@
// Forward declarations.
class GURL;
class SkBitmap;
+class DictionaryValue;
+class ListValue;
namespace gfx {
class Point;
@@ -359,6 +361,22 @@ struct ParamTraits<SkBitmap> {
};
template <>
+struct ParamTraits<DictionaryValue> {
+ typedef DictionaryValue param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* r);
+ static void Log(const param_type& p, std::wstring* l);
+};
+
+template <>
+struct ParamTraits<ListValue> {
+ typedef ListValue param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* r);
+ static void Log(const param_type& p, std::wstring* l);
+};
+
+template <>
struct ParamTraits<std::string> {
typedef std::string param_type;
static void Write(Message* m, const param_type& p) {