summaryrefslogtreecommitdiffstats
path: root/ppapi/proxy/serialized_var.cc
diff options
context:
space:
mode:
Diffstat (limited to 'ppapi/proxy/serialized_var.cc')
-rw-r--r--ppapi/proxy/serialized_var.cc457
1 files changed, 457 insertions, 0 deletions
diff --git a/ppapi/proxy/serialized_var.cc b/ppapi/proxy/serialized_var.cc
new file mode 100644
index 0000000..a76f219
--- /dev/null
+++ b/ppapi/proxy/serialized_var.cc
@@ -0,0 +1,457 @@
+// 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, 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].GetStringPtr());
+ }
+}
+
+// ReceiveSerializedVarReturnValue ---------------------------------------------
+
+ReceiveSerializedVarReturnValue::ReceiveSerializedVarReturnValue() {
+}
+
+PP_Var ReceiveSerializedVarReturnValue::Return(Dispatcher* dispatcher) {
+ set_serialization_rules(dispatcher->serialization_rules());
+ SetVar(serialization_rules()->ReceivePassRef(GetIncompleteVar(),
+ GetString()));
+ return 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.
+ SetVar(serialization_rules()->ReceivePassRef(GetIncompleteVar(),
+ GetString()));
+ *exception_ = 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 (GetVar().type == PP_VARTYPE_OBJECT)
+ serialization_rules()->ReleaseObjectRef(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_.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_.set_cleanup_mode(SerializedVar::END_RECEIVE_CALLER_OWNED);
+
+ serialized_.SetVar(
+ serialized_.serialization_rules()->BeginReceiveCallerOwned(
+ serialized_.GetIncompleteVar(), serialized_.GetStringPtr()));
+ return serialized_.GetVar();
+}
+
+// SerializedVarVectorReceiveInput ---------------------------------------------
+
+SerializedVarVectorReceiveInput::SerializedVarVectorReceiveInput(
+ const std::vector<SerializedVar>& serialized)
+ : serialized_(serialized) {
+}
+
+SerializedVarVectorReceiveInput::~SerializedVarVectorReceiveInput() {
+ for (size_t i = 0; i < deserialized_.size(); i++) {
+ serialized_[i].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].set_serialization_rules(dispatcher->serialization_rules());
+
+ serialized_[i].SetVar(
+ serialized_[i].serialization_rules()->BeginReceiveCallerOwned(
+ serialized_[i].GetIncompleteVar(), serialized_[i].GetStringPtr()));
+ deserialized_[i] = serialized_[i].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_->set_serialization_rules(dispatcher->serialization_rules());
+ serialized_->SetVar(var);
+
+ // Var must clean up after our BeginSendPassRef call.
+ serialized_->set_cleanup_mode(SerializedVar::END_SEND_PASS_REF);
+
+ dispatcher->serialization_rules()->BeginSendPassRef(
+ serialized_->GetIncompleteVar(), serialized_->GetStringPtr());
+}
+
+// SerializedVarOutParam -------------------------------------------------------
+
+SerializedVarOutParam::SerializedVarOutParam(SerializedVar* serialized)
+ : serialized_(serialized),
+ writable_var_(PP_MakeUndefined()) {
+}
+
+SerializedVarOutParam::~SerializedVarOutParam() {
+ if (serialized_->serialization_rules()) {
+ // When unset, OutParam wasn't called. We'll just leave the var untouched
+ // in that case.
+ serialized_->SetVar(writable_var_);
+ serialized_->serialization_rules()->BeginSendPassRef(
+ writable_var_, serialized_->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_->set_cleanup_mode(SerializedVar::END_SEND_PASS_REF);
+ }
+}
+
+PP_Var* SerializedVarOutParam::OutParam(Dispatcher* dispatcher) {
+ serialized_->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
+