| Index: ppapi/proxy/serialized_var.cc
|
| ===================================================================
|
| --- ppapi/proxy/serialized_var.cc (revision 0)
|
| +++ ppapi/proxy/serialized_var.cc (revision 0)
|
| @@ -0,0 +1,465 @@
|
| +// Copyright (c) 2010 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 "ppapi/proxy/serialized_var.h"
|
| +
|
| +#include "base/logging.h"
|
| +#include "ipc/ipc_message_utils.h"
|
| +#include "ppapi/proxy/dispatcher.h"
|
| +#include "ppapi/proxy/ppapi_param_traits.h"
|
| +#include "ppapi/proxy/var_serialization_rules.h"
|
| +
|
| +namespace pp {
|
| +namespace proxy {
|
| +
|
| +// SerializedVar::Inner --------------------------------------------------------
|
| +
|
| +SerializedVar::Inner::Inner()
|
| + : serialization_rules_(NULL),
|
| + var_(PP_MakeUndefined()),
|
| + cleanup_mode_(CLEANUP_NONE) {
|
| +#ifndef NDEBUG
|
| + has_been_serialized_ = false;
|
| + has_been_deserialized_ = false;
|
| +#endif
|
| +}
|
| +
|
| +SerializedVar::Inner::Inner(VarSerializationRules* serialization_rules)
|
| + : serialization_rules_(serialization_rules),
|
| + var_(PP_MakeUndefined()),
|
| + cleanup_mode_(CLEANUP_NONE) {
|
| +#ifndef NDEBUG
|
| + has_been_serialized_ = false;
|
| + has_been_deserialized_ = false;
|
| +#endif
|
| +}
|
| +
|
| +SerializedVar::Inner::Inner(VarSerializationRules* serialization_rules,
|
| + const PP_Var& var)
|
| + : serialization_rules_(serialization_rules),
|
| + var_(var),
|
| + cleanup_mode_(CLEANUP_NONE) {
|
| +#ifndef NDEBUG
|
| + has_been_serialized_ = false;
|
| + has_been_deserialized_ = false;
|
| +#endif
|
| +}
|
| +
|
| +SerializedVar::Inner::~Inner() {
|
| + switch (cleanup_mode_) {
|
| + case END_SEND_PASS_REF:
|
| + serialization_rules_->EndSendPassRef(var_);
|
| + break;
|
| + case END_RECEIVE_CALLER_OWNED:
|
| + serialization_rules_->EndReceiveCallerOwned(var_);
|
| + break;
|
| + default:
|
| + break;
|
| + }
|
| +}
|
| +
|
| +PP_Var SerializedVar::Inner::GetVar() const {
|
| + DCHECK(serialization_rules_);
|
| +
|
| + // If we're a string var, we should have already converted the string value
|
| + // to a var ID.
|
| + DCHECK(var_.type != PP_VARTYPE_STRING || var_.value.as_id != 0);
|
| + return var_;
|
| +}
|
| +
|
| +PP_Var SerializedVar::Inner::GetIncompleteVar() const {
|
| + DCHECK(serialization_rules_);
|
| + return var_;
|
| +}
|
| +
|
| +void SerializedVar::Inner::SetVar(PP_Var var) {
|
| + // Sanity check, when updating the var we should have received a
|
| + // serialization rules pointer already.
|
| + DCHECK(serialization_rules_);
|
| + var_ = var;
|
| +}
|
| +
|
| +const std::string& SerializedVar::Inner::GetString() const {
|
| + DCHECK(serialization_rules_);
|
| + return string_value_;
|
| +}
|
| +
|
| +std::string* SerializedVar::Inner::GetStringPtr() {
|
| + DCHECK(serialization_rules_);
|
| + return &string_value_;
|
| +}
|
| +
|
| +void SerializedVar::Inner::WriteToMessage(IPC::Message* m) const {
|
| + // When writing to the IPC messages, a serization rules handler should
|
| + // always have been set.
|
| + //
|
| + // When sending a message, it should be difficult to trigger this if you're
|
| + // using the SerializedVarSendInput class and giving a non-NULL dispatcher.
|
| + // Make sure you're using the proper "Send" helper class.
|
| + //
|
| + // It should be more common to see this when handling an incoming message
|
| + // that returns a var. This means the message handler didn't write to the
|
| + // output parameter, or possibly you used the wrong helper class
|
| + // (normally SerializedVarReturnValue).
|
| + DCHECK(serialization_rules_);
|
| +
|
| +#ifndef NDEBUG
|
| + // We should only be serializing something once.
|
| + DCHECK(!has_been_serialized_);
|
| + has_been_serialized_ = true;
|
| +#endif
|
| +
|
| + // If the var is not a string type, we should not have ended up with any
|
| + // string data.
|
| + DCHECK(var_.type == PP_VARTYPE_STRING || string_value_.empty());
|
| +
|
| + m->WriteInt(static_cast<int>(var_.type));
|
| + switch (var_.type) {
|
| + case PP_VARTYPE_UNDEFINED:
|
| + case PP_VARTYPE_NULL:
|
| + // These don't need any data associated with them other than the type we
|
| + // just serialized.
|
| + break;
|
| + case PP_VARTYPE_BOOL:
|
| + m->WriteBool(var_.value.as_bool);
|
| + break;
|
| + case PP_VARTYPE_INT32:
|
| + m->WriteInt(var_.value.as_int);
|
| + break;
|
| + case PP_VARTYPE_DOUBLE:
|
| + IPC::ParamTraits<double>::Write(m, var_.value.as_double);
|
| + break;
|
| + case PP_VARTYPE_STRING:
|
| + // TODO(brettw) in the case of an invalid string ID, it would be nice
|
| + // to send something to the other side such that a 0 ID would be
|
| + // generated there. Then the function implementing the interface can
|
| + // handle the invalid string as if it was in process rather than seeing
|
| + // what looks like a valid empty string.
|
| + m->WriteString(string_value_);
|
| + break;
|
| + case PP_VARTYPE_OBJECT:
|
| + m->WriteInt64(var_.value.as_id);
|
| + break;
|
| + }
|
| +}
|
| +
|
| +bool SerializedVar::Inner::ReadFromMessage(const IPC::Message* m, void** iter) {
|
| +#ifndef NDEBUG
|
| + // We should only deserialize something once or will end up with leaked
|
| + // references.
|
| + //
|
| + // One place this has happened in the past is using
|
| + // std::vector<SerializedVar>.resize(). If you're doing this manually instead
|
| + // of using the helper classes for handling in/out vectors of vars, be
|
| + // sure you use the same pattern as the SerializedVarVector classes.
|
| + DCHECK(!has_been_deserialized_);
|
| + has_been_deserialized_ = true;
|
| +#endif
|
| +
|
| + // When reading, the dispatcher should be set when we get a Deserialize
|
| + // call (which will supply a dispatcher).
|
| + int type;
|
| + if (!m->ReadInt(iter, &type))
|
| + return false;
|
| +
|
| + bool success = false;
|
| + switch (type) {
|
| + case PP_VARTYPE_UNDEFINED:
|
| + case PP_VARTYPE_NULL:
|
| + // These don't have any data associated with them other than the type we
|
| + // just serialized.
|
| + success = true;
|
| + break;
|
| + case PP_VARTYPE_BOOL:
|
| + success = m->ReadBool(iter, &var_.value.as_bool);
|
| + break;
|
| + case PP_VARTYPE_INT32:
|
| + success = m->ReadInt(iter, &var_.value.as_int);
|
| + break;
|
| + case PP_VARTYPE_DOUBLE:
|
| + success = IPC::ParamTraits<double>::Read(m, iter, &var_.value.as_double);
|
| + break;
|
| + case PP_VARTYPE_STRING:
|
| + success = m->ReadString(iter, &string_value_);
|
| + var_.value.as_id = 0;
|
| + break;
|
| + case PP_VARTYPE_OBJECT:
|
| + success = m->ReadInt64(iter, &var_.value.as_id);
|
| + break;
|
| + default:
|
| + // Leave success as false.
|
| + break;
|
| + }
|
| +
|
| + // All success cases get here. We avoid writing the type above so that the
|
| + // output param is untouched (defaults to VARTYPE_UNDEFINED) even in the
|
| + // failure case.
|
| + if (success)
|
| + var_.type = static_cast<PP_VarType>(type);
|
| + return success;
|
| +}
|
| +
|
| +// SerializedVar ---------------------------------------------------------------
|
| +
|
| +SerializedVar::SerializedVar() : inner_(new Inner) {
|
| +}
|
| +
|
| +SerializedVar::SerializedVar(VarSerializationRules* serialization_rules)
|
| + : inner_(new Inner(serialization_rules)) {
|
| +}
|
| +
|
| +SerializedVar::SerializedVar(VarSerializationRules* serialization_rules,
|
| + const PP_Var& var)
|
| + : inner_(new Inner(serialization_rules, var)) {
|
| +}
|
| +
|
| +SerializedVar::~SerializedVar() {
|
| +}
|
| +
|
| +// SerializedVarSendInput ------------------------------------------------------
|
| +
|
| +SerializedVarSendInput::SerializedVarSendInput(Dispatcher* dispatcher,
|
| + const PP_Var& var)
|
| + : SerializedVar(dispatcher->serialization_rules(), var) {
|
| + dispatcher->serialization_rules()->SendCallerOwned(var,
|
| + inner_->GetStringPtr());
|
| +}
|
| +
|
| +// static
|
| +void SerializedVarSendInput::ConvertVector(Dispatcher* dispatcher,
|
| + const PP_Var* input,
|
| + size_t input_count,
|
| + std::vector<SerializedVar>* output) {
|
| + output->resize(input_count);
|
| + for (size_t i = 0; i < input_count; i++) {
|
| + (*output)[i] = SerializedVar(dispatcher->serialization_rules(), input[i]);
|
| + dispatcher->serialization_rules()->SendCallerOwned(
|
| + input[i], (*output)[i].inner_->GetStringPtr());
|
| + }
|
| +}
|
| +
|
| +// ReceiveSerializedVarReturnValue ---------------------------------------------
|
| +
|
| +ReceiveSerializedVarReturnValue::ReceiveSerializedVarReturnValue() {
|
| +}
|
| +
|
| +PP_Var ReceiveSerializedVarReturnValue::Return(Dispatcher* dispatcher) {
|
| + inner_->set_serialization_rules(dispatcher->serialization_rules());
|
| + inner_->SetVar(inner_->serialization_rules()->ReceivePassRef(
|
| + inner_->GetIncompleteVar(), inner_->GetString()));
|
| + return inner_->GetVar();
|
| +}
|
| +
|
| +// ReceiveSerializedException --------------------------------------------------
|
| +
|
| +ReceiveSerializedException::ReceiveSerializedException(Dispatcher* dispatcher,
|
| + PP_Var* exception)
|
| + : SerializedVar(dispatcher->serialization_rules()),
|
| + exception_(exception) {
|
| +}
|
| +
|
| +ReceiveSerializedException::~ReceiveSerializedException() {
|
| + if (exception_) {
|
| + // When an output exception is specified, it will take ownership of the
|
| + // reference.
|
| + inner_->SetVar(inner_->serialization_rules()->ReceivePassRef(
|
| + inner_->GetIncompleteVar(), inner_->GetString()));
|
| + *exception_ = inner_->GetVar();
|
| + } else {
|
| + // When no output exception is specified, the browser thinks we have a ref
|
| + // to an object that we don't want (this will happen only in the plugin
|
| + // since the browser will always specify an out exception for the plugin to
|
| + // write into).
|
| + //
|
| + // Strings don't need this handling since we can just avoid creating a
|
| + // Var from the std::string in the first place.
|
| + if (inner_->GetVar().type == PP_VARTYPE_OBJECT)
|
| + inner_->serialization_rules()->ReleaseObjectRef(inner_->GetVar());
|
| + }
|
| +}
|
| +
|
| +bool ReceiveSerializedException::IsThrown() const {
|
| + return exception_ && exception_->type != PP_VARTYPE_UNDEFINED;
|
| +}
|
| +
|
| +// ReceiveSerializedVarVectorOutParam ------------------------------------------
|
| +
|
| +ReceiveSerializedVarVectorOutParam::ReceiveSerializedVarVectorOutParam(
|
| + Dispatcher* dispatcher,
|
| + uint32_t* output_count,
|
| + PP_Var** output)
|
| + : dispatcher_(dispatcher),
|
| + output_count_(output_count),
|
| + output_(output) {
|
| +}
|
| +
|
| +ReceiveSerializedVarVectorOutParam::~ReceiveSerializedVarVectorOutParam() {
|
| + *output_count_ = static_cast<uint32_t>(vector_.size());
|
| + if (!vector_.size()) {
|
| + *output_ = NULL;
|
| + return;
|
| + }
|
| +
|
| + *output_ = static_cast<PP_Var*>(malloc(vector_.size() * sizeof(PP_Var)));
|
| + for (size_t i = 0; i < vector_.size(); i++) {
|
| + // Here we just mimic what happens when returning a value.
|
| + ReceiveSerializedVarReturnValue converted;
|
| + SerializedVar* serialized = &converted;
|
| + *serialized = vector_[i];
|
| + (*output_)[i] = converted.Return(dispatcher_);
|
| + }
|
| +}
|
| +
|
| +std::vector<SerializedVar>* ReceiveSerializedVarVectorOutParam::OutParam() {
|
| + return &vector_;
|
| +}
|
| +
|
| +// SerializedVarReceiveInput ---------------------------------------------------
|
| +
|
| +SerializedVarReceiveInput::SerializedVarReceiveInput(
|
| + const SerializedVar& serialized)
|
| + : serialized_(serialized),
|
| + dispatcher_(NULL),
|
| + var_(PP_MakeUndefined()) {
|
| +}
|
| +
|
| +SerializedVarReceiveInput::~SerializedVarReceiveInput() {
|
| +}
|
| +
|
| +PP_Var SerializedVarReceiveInput::Get(Dispatcher* dispatcher) {
|
| + serialized_.inner_->set_serialization_rules(
|
| + dispatcher->serialization_rules());
|
| +
|
| + // Ensure that when the serialized var goes out of scope it cleans up the
|
| + // stuff we're making in BeginReceiveCallerOwned.
|
| + serialized_.inner_->set_cleanup_mode(SerializedVar::END_RECEIVE_CALLER_OWNED);
|
| +
|
| + serialized_.inner_->SetVar(
|
| + serialized_.inner_->serialization_rules()->BeginReceiveCallerOwned(
|
| + serialized_.inner_->GetIncompleteVar(),
|
| + serialized_.inner_->GetStringPtr()));
|
| + return serialized_.inner_->GetVar();
|
| +}
|
| +
|
| +// SerializedVarVectorReceiveInput ---------------------------------------------
|
| +
|
| +SerializedVarVectorReceiveInput::SerializedVarVectorReceiveInput(
|
| + const std::vector<SerializedVar>& serialized)
|
| + : serialized_(serialized) {
|
| +}
|
| +
|
| +SerializedVarVectorReceiveInput::~SerializedVarVectorReceiveInput() {
|
| + for (size_t i = 0; i < deserialized_.size(); i++) {
|
| + serialized_[i].inner_->serialization_rules()->EndReceiveCallerOwned(
|
| + deserialized_[i]);
|
| + }
|
| +}
|
| +
|
| +PP_Var* SerializedVarVectorReceiveInput::Get(Dispatcher* dispatcher,
|
| + uint32_t* array_size) {
|
| + deserialized_.resize(serialized_.size());
|
| + for (size_t i = 0; i < serialized_.size(); i++) {
|
| + // The vector must be able to clean themselves up after this call is
|
| + // torn down.
|
| + serialized_[i].inner_->set_serialization_rules(
|
| + dispatcher->serialization_rules());
|
| +
|
| + serialized_[i].inner_->SetVar(
|
| + serialized_[i].inner_->serialization_rules()->BeginReceiveCallerOwned(
|
| + serialized_[i].inner_->GetIncompleteVar(),
|
| + serialized_[i].inner_->GetStringPtr()));
|
| + deserialized_[i] = serialized_[i].inner_->GetVar();
|
| + }
|
| +
|
| + *array_size = static_cast<uint32_t>(serialized_.size());
|
| + return deserialized_.size() > 0 ? &deserialized_[0] : NULL;
|
| +}
|
| +
|
| +// SerializedVarReturnValue ----------------------------------------------------
|
| +
|
| +SerializedVarReturnValue::SerializedVarReturnValue(SerializedVar* serialized)
|
| + : serialized_(serialized) {
|
| +}
|
| +
|
| +void SerializedVarReturnValue::Return(Dispatcher* dispatcher,
|
| + const PP_Var& var) {
|
| + serialized_->inner_->set_serialization_rules(
|
| + dispatcher->serialization_rules());
|
| + serialized_->inner_->SetVar(var);
|
| +
|
| + // Var must clean up after our BeginSendPassRef call.
|
| + serialized_->inner_->set_cleanup_mode(SerializedVar::END_SEND_PASS_REF);
|
| +
|
| + dispatcher->serialization_rules()->BeginSendPassRef(
|
| + serialized_->inner_->GetIncompleteVar(),
|
| + serialized_->inner_->GetStringPtr());
|
| +}
|
| +
|
| +// SerializedVarOutParam -------------------------------------------------------
|
| +
|
| +SerializedVarOutParam::SerializedVarOutParam(SerializedVar* serialized)
|
| + : serialized_(serialized),
|
| + writable_var_(PP_MakeUndefined()) {
|
| +}
|
| +
|
| +SerializedVarOutParam::~SerializedVarOutParam() {
|
| + if (serialized_->inner_->serialization_rules()) {
|
| + // When unset, OutParam wasn't called. We'll just leave the var untouched
|
| + // in that case.
|
| + serialized_->inner_->SetVar(writable_var_);
|
| + serialized_->inner_->serialization_rules()->BeginSendPassRef(
|
| + writable_var_, serialized_->inner_->GetStringPtr());
|
| +
|
| + // Normally the current object will be created on the stack to wrap a
|
| + // SerializedVar and won't have a scope around the actual IPC send. So we
|
| + // need to tell the SerializedVar to do the begin/end send pass ref calls.
|
| + serialized_->inner_->set_cleanup_mode(SerializedVar::END_SEND_PASS_REF);
|
| + }
|
| +}
|
| +
|
| +PP_Var* SerializedVarOutParam::OutParam(Dispatcher* dispatcher) {
|
| + serialized_->inner_->set_serialization_rules(
|
| + dispatcher->serialization_rules());
|
| + return &writable_var_;
|
| +}
|
| +
|
| +// SerializedVarVectorOutParam -------------------------------------------------
|
| +
|
| +SerializedVarVectorOutParam::SerializedVarVectorOutParam(
|
| + std::vector<SerializedVar>* serialized)
|
| + : dispatcher_(NULL),
|
| + serialized_(serialized),
|
| + count_(0),
|
| + array_(NULL) {
|
| +}
|
| +
|
| +SerializedVarVectorOutParam::~SerializedVarVectorOutParam() {
|
| + DCHECK(dispatcher_);
|
| +
|
| + // Convert the array written by the pepper code to the serialized structure.
|
| + // Note we can't use resize here, we have to allocate a new SerializedVar
|
| + // for each serialized item. See ParamTraits<vector<SerializedVar>>::Read.
|
| + serialized_->reserve(count_);
|
| + for (uint32_t i = 0; i < count_; i++) {
|
| + // Just mimic what we do for regular OutParams.
|
| + SerializedVar var;
|
| + SerializedVarOutParam out(&var);
|
| + *out.OutParam(dispatcher_) = array_[i];
|
| + serialized_->push_back(var);
|
| + }
|
| +
|
| + // When returning arrays, the pepper code expects the caller to take
|
| + // ownership of the array.
|
| + free(array_);
|
| +}
|
| +
|
| +PP_Var** SerializedVarVectorOutParam::ArrayOutParam(Dispatcher* dispatcher) {
|
| + DCHECK(!dispatcher_); // Should only be called once.
|
| + dispatcher_ = dispatcher;
|
| + return &array_;
|
| +}
|
| +
|
| +} // namespace proxy
|
| +} // namespace pp
|
| +
|
|
|
| Property changes on: ppapi/proxy/serialized_var.cc
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|