| // Copyright (c) 2009 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 "ipc/ipc_message_utils.h" |
| |
| #include "base/file_path.h" |
| #include "base/json/json_writer.h" |
| #include "base/nullable_string16.h" |
| #include "base/scoped_ptr.h" |
| #include "base/string_number_conversions.h" |
| #include "base/time.h" |
| #include "base/utf_string_conversions.h" |
| #include "base/values.h" |
| #if defined(OS_POSIX) |
| #include "ipc/file_descriptor_set_posix.h" |
| #endif |
| #include "ipc/ipc_channel_handle.h" |
| |
| namespace IPC { |
| |
| const int kMaxRecursionDepth = 100; |
| |
| // 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: { |
| const BinaryValue* binary = static_cast<const BinaryValue*>(value); |
| m->WriteData(binary->GetBuffer(), static_cast<int>(binary->GetSize())); |
| break; |
| } |
| case Value::TYPE_DICTIONARY: { |
| const DictionaryValue* dict = static_cast<const DictionaryValue*>(value); |
| |
| WriteParam(m, static_cast<int>(dict->size())); |
| |
| for (DictionaryValue::key_iterator it = dict->begin_keys(); |
| it != dict->end_keys(); ++it) { |
| Value* subval; |
| if (dict->GetWithoutPathExpansion(*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::string 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: { |
| const char* data; |
| int length; |
| if (!m->ReadData(iter, &data, &length)) |
| return false; |
| *value = BinaryValue::CreateWithCopiedBuffer(data, length); |
| 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<int>::Log(const param_type& p, std::string* l) { |
| l->append(base::IntToString(p)); |
| } |
| |
| void ParamTraits<unsigned int>::Log(const param_type& p, std::string* l) { |
| l->append(base::UintToString(p)); |
| } |
| |
| void ParamTraits<long>::Log(const param_type& p, std::string* l) { |
| l->append(base::Int64ToString(static_cast<int64>(p))); |
| } |
| |
| void ParamTraits<unsigned long>::Log(const param_type& p, std::string* l) { |
| l->append(base::Uint64ToString(static_cast<uint64>(p))); |
| } |
| |
| void ParamTraits<long long>::Log(const param_type& p, std::string* l) { |
| l->append(base::Int64ToString(static_cast<int64>(p))); |
| } |
| |
| void ParamTraits<unsigned long long>::Log(const param_type& p, std::string* l) { |
| l->append(base::Uint64ToString(p)); |
| } |
| |
| void ParamTraits<base::Time>::Write(Message* m, const param_type& p) { |
| ParamTraits<int64>::Write(m, p.ToInternalValue()); |
| } |
| |
| bool ParamTraits<base::Time>::Read(const Message* m, void** iter, |
| param_type* r) { |
| int64 value; |
| if (!ParamTraits<int64>::Read(m, iter, &value)) |
| return false; |
| *r = base::Time::FromInternalValue(value); |
| return true; |
| } |
| |
| void ParamTraits<base::Time>::Log(const param_type& p, std::string* l) { |
| ParamTraits<int64>::Log(p.ToInternalValue(), l); |
| } |
| |
| 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::string* l) { |
| std::string json; |
| base::JSONWriter::Write(&p, false, &json); |
| l->append(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::string* l) { |
| std::string json; |
| base::JSONWriter::Write(&p, false, &json); |
| l->append(json); |
| } |
| |
| void ParamTraits<std::wstring>::Log(const param_type& p, std::string* l) { |
| l->append(WideToUTF8(p)); |
| } |
| |
| void ParamTraits<NullableString16>::Write(Message* m, const param_type& p) { |
| WriteParam(m, p.string()); |
| WriteParam(m, p.is_null()); |
| } |
| |
| bool ParamTraits<NullableString16>::Read(const Message* m, void** iter, |
| param_type* r) { |
| string16 string; |
| if (!ReadParam(m, iter, &string)) |
| return false; |
| bool is_null; |
| if (!ReadParam(m, iter, &is_null)) |
| return false; |
| *r = NullableString16(string, is_null); |
| return true; |
| } |
| |
| void ParamTraits<NullableString16>::Log(const param_type& p, std::string* l) { |
| l->append("("); |
| LogParam(p.string(), l); |
| l->append(", "); |
| LogParam(p.is_null(), l); |
| l->append(")"); |
| } |
| |
| #if !defined(WCHAR_T_IS_UTF16) |
| void ParamTraits<string16>::Log(const param_type& p, std::string* l) { |
| l->append(UTF16ToUTF8(p)); |
| } |
| #endif |
| |
| |
| void ParamTraits<FilePath>::Write(Message* m, const param_type& p) { |
| ParamTraits<FilePath::StringType>::Write(m, p.value()); |
| } |
| |
| bool ParamTraits<FilePath>::Read(const Message* m, void** iter, param_type* r) { |
| FilePath::StringType value; |
| if (!ParamTraits<FilePath::StringType>::Read(m, iter, &value)) |
| return false; |
| *r = FilePath(value); |
| return true; |
| } |
| |
| void ParamTraits<FilePath>::Log(const param_type& p, std::string* l) { |
| ParamTraits<FilePath::StringType>::Log(p.value(), l); |
| } |
| |
| #if defined(OS_POSIX) |
| void ParamTraits<base::FileDescriptor>::Write(Message* m, const param_type& p) { |
| const bool valid = p.fd >= 0; |
| WriteParam(m, valid); |
| |
| if (valid) { |
| if (!m->WriteFileDescriptor(p)) |
| NOTREACHED(); |
| } |
| } |
| |
| bool ParamTraits<base::FileDescriptor>::Read(const Message* m, void** iter, |
| param_type* r) { |
| bool valid; |
| if (!ReadParam(m, iter, &valid)) |
| return false; |
| |
| if (!valid) { |
| r->fd = -1; |
| r->auto_close = false; |
| return true; |
| } |
| |
| return m->ReadFileDescriptor(iter, r); |
| } |
| |
| void ParamTraits<base::FileDescriptor>::Log(const param_type& p, |
| std::string* l) { |
| if (p.auto_close) { |
| l->append(StringPrintf("FD(%d auto-close)", p.fd)); |
| } else { |
| l->append(StringPrintf("FD(%d)", p.fd)); |
| } |
| } |
| #endif // defined(OS_POSIX) |
| |
| void ParamTraits<IPC::ChannelHandle>::Write(Message* m, const param_type& p) { |
| WriteParam(m, p.name); |
| #if defined(OS_POSIX) |
| WriteParam(m, p.socket); |
| #endif |
| } |
| |
| bool ParamTraits<IPC::ChannelHandle>::Read(const Message* m, void** iter, |
| param_type* r) { |
| return ReadParam(m, iter, &r->name) |
| #if defined(OS_POSIX) |
| && ReadParam(m, iter, &r->socket) |
| #endif |
| ; |
| } |
| |
| void ParamTraits<IPC::ChannelHandle>::Log(const param_type& p, |
| std::string* l) { |
| l->append(StringPrintf("ChannelHandle(%s", p.name.c_str())); |
| #if defined(OS_POSIX) |
| ParamTraits<base::FileDescriptor>::Log(p.socket, l); |
| #endif |
| l->append(")"); |
| } |
| |
| } // namespace IPC |