// 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/json/json_writer.h" #include "base/scoped_ptr.h" #include "base/time.h" #include "base/values.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(value); m->WriteData(binary->GetBuffer(), binary->GetSize()); break; } case Value::TYPE_DICTIONARY: { const DictionaryValue* dict = static_cast(value); WriteParam(m, static_cast(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(value); WriteParam(m, static_cast(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: { 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 val(new DictionaryValue()); if (!ReadDictionaryValue(m, iter, val.get(), recursion)) return false; *value = val.release(); break; } case Value::TYPE_LIST: { scoped_ptr val(new ListValue()); if (!ReadListValue(m, iter, val.get(), recursion)) return false; *value = val.release(); break; } default: return false; } return true; } void ParamTraits::Write(Message* m, const param_type& p) { WriteValue(m, &p, 0); } bool ParamTraits::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::Log(const param_type& p, std::wstring* l) { std::string json; base::JSONWriter::Write(&p, false, &json); l->append(UTF8ToWide(json)); } void ParamTraits::Write(Message* m, const param_type& p) { WriteValue(m, &p, 0); } bool ParamTraits::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::Log(const param_type& p, std::wstring* l) { std::string json; base::JSONWriter::Write(&p, false, &json); l->append(UTF8ToWide(json)); } } // namespace IPC