diff options
author | mpcomplete@google.com <mpcomplete@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-21 01:01:59 +0000 |
---|---|---|
committer | mpcomplete@google.com <mpcomplete@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-21 01:01:59 +0000 |
commit | 584f2b2101da22d458c24fdaf9ccc8112834508e (patch) | |
tree | 8e6728ce079e61cc216974c795cfb697ebce447b | |
parent | a37ebbc3c152f9e2ff6b1e1726cf6cd2ad4da8a0 (diff) | |
download | chromium_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.cc | 59 | ||||
-rw-r--r-- | chrome/common/ipc_message_utils.cc | 224 | ||||
-rw-r--r-- | chrome/common/ipc_message_utils.h | 18 |
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) { |