1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Scriptable plugin implementation. 6 7 #include "ppapi/native_client/src/trusted/plugin/scriptable_plugin.h" 8 9 #include <string.h> 10 11 #include <sstream> 12 #include <string> 13 #include <vector> 14 15 #include "native_client/src/include/nacl_macros.h" 16 #include "native_client/src/include/nacl_string.h" 17 #include "native_client/src/include/portability.h" 18 #include "native_client/src/shared/platform/nacl_check.h" 19 #include "native_client/src/shared/srpc/nacl_srpc.h" 20 #include "ppapi/native_client/src/trusted/plugin/plugin.h" 21 #include "ppapi/native_client/src/trusted/plugin/utility.h" 22 23 24 namespace plugin { 25 26 namespace { 27 28 pp::Var Error(const nacl::string& call_name, const char* caller, 29 const char* error, pp::Var* exception) { 30 nacl::stringstream error_stream; 31 error_stream << call_name << ": " << error; 32 if (!exception->is_undefined()) { 33 error_stream << " - " + exception->AsString(); 34 } 35 // Get the error string in 2 steps; otherwise, the temporary string returned 36 // by the stream is destructed, causing a dangling pointer. 37 std::string str = error_stream.str(); 38 const char* e = str.c_str(); 39 PLUGIN_PRINTF(("ScriptablePlugin::%s (%s)\n", caller, e)); 40 *exception = pp::Var(e); 41 return pp::Var(); 42 } 43 44 // In JavaScript, foo[1] is equivalent to foo["1"], so map both indexed and 45 // string names to a string. 46 nacl::string NameAsString(const pp::Var& name) { 47 if (name.is_string()) 48 return name.AsString(); 49 CHECK(name.is_int()); 50 nacl::stringstream namestream; 51 namestream << name.AsInt(); 52 return namestream.str(); 53 } 54 55 // Returns a pp::Var corresponding to |arg| or void. Sets |exception| on error. 56 pp::Var NaClSrpcArgToPPVar(const NaClSrpcArg* arg, pp::Var* exception) { 57 PLUGIN_PRINTF((" NaClSrpcArgToPPVar (arg->tag='%c')\n", arg->tag)); 58 pp::Var var; 59 switch (arg->tag) { 60 case NACL_SRPC_ARG_TYPE_BOOL: 61 var = pp::Var(arg->u.bval != 0); 62 break; 63 case NACL_SRPC_ARG_TYPE_DOUBLE: 64 var = pp::Var(arg->u.dval); 65 break; 66 case NACL_SRPC_ARG_TYPE_INT: 67 var = pp::Var(arg->u.ival); 68 break; 69 case NACL_SRPC_ARG_TYPE_LONG: 70 // PPAPI does not have a 64-bit integral type. Downcast. 71 var = pp::Var(static_cast<int32_t>(arg->u.lval)); 72 break; 73 case NACL_SRPC_ARG_TYPE_STRING: 74 var = pp::Var(arg->arrays.str); 75 break; 76 case NACL_SRPC_ARG_TYPE_CHAR_ARRAY: 77 case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY: 78 case NACL_SRPC_ARG_TYPE_INT_ARRAY: 79 case NACL_SRPC_ARG_TYPE_LONG_ARRAY: 80 case NACL_SRPC_ARG_TYPE_OBJECT: 81 case NACL_SRPC_ARG_TYPE_HANDLE: 82 case NACL_SRPC_ARG_TYPE_VARIANT_ARRAY: 83 case NACL_SRPC_ARG_TYPE_INVALID: 84 default: 85 *exception = "variant array and invalid argument types are not supported"; 86 } 87 PLUGIN_PRINTF((" NaClSrpcArgToPPVar (return var=%s, exception=%s)\n", 88 var.DebugString().c_str(), exception->DebugString().c_str())); 89 return var; 90 } 91 92 } // namespace 93 94 ScriptablePlugin::ScriptablePlugin(Plugin* plugin) 95 : var_(NULL), num_unref_calls_(0), plugin_(plugin) { 96 PLUGIN_PRINTF(("ScriptablePlugin::ScriptablePlugin (this=%p, plugin=%p)\n", 97 static_cast<void*>(this), 98 static_cast<void*>(plugin))); 99 } 100 101 ScriptablePlugin::~ScriptablePlugin() { 102 PLUGIN_PRINTF(("ScriptablePlugin::~ScriptablePlugin (this=%p)\n", 103 static_cast<void*>(this))); 104 PLUGIN_PRINTF(("ScriptablePlugin::~ScriptablePlugin (this=%p, return)\n", 105 static_cast<void*>(this))); 106 } 107 108 void ScriptablePlugin::Unref(ScriptablePlugin** handle) { 109 if (*handle != NULL) { 110 (*handle)->Unref(); 111 *handle = NULL; 112 } 113 } 114 115 ScriptablePlugin* ScriptablePlugin::NewPlugin(Plugin* plugin) { 116 PLUGIN_PRINTF(("ScriptablePlugin::NewPlugin (plugin=%p)\n", 117 static_cast<void*>(plugin))); 118 if (plugin == NULL) { 119 return NULL; 120 } 121 ScriptablePlugin* scriptable_plugin = new ScriptablePlugin(plugin); 122 if (scriptable_plugin == NULL) { 123 return NULL; 124 } 125 PLUGIN_PRINTF(("ScriptablePlugin::NewPlugin (return %p)\n", 126 static_cast<void*>(scriptable_plugin))); 127 return scriptable_plugin; 128 } 129 130 bool ScriptablePlugin::HasProperty(const pp::Var& name, pp::Var* exception) { 131 UNREFERENCED_PARAMETER(exception); 132 PLUGIN_PRINTF(("ScriptablePlugin::HasProperty (this=%p, name=%s)\n", 133 static_cast<void*>(this), name.DebugString().c_str())); 134 if (plugin_ == NULL) { 135 return false; 136 } 137 if (!name.is_string() && !name.is_int()) 138 return false; 139 bool has_property = plugin_->HasProperty(name.AsString()); 140 PLUGIN_PRINTF(("ScriptablePlugin::HasProperty (has_property=%d)\n", 141 has_property)); 142 return has_property; 143 } 144 145 146 bool ScriptablePlugin::HasMethod(const pp::Var& name, pp::Var* exception) { 147 UNREFERENCED_PARAMETER(exception); 148 PLUGIN_PRINTF(("ScriptablePlugin::HasMethod (this=%p, name='%s')\n", 149 static_cast<void*>(this), name.DebugString().c_str())); 150 return false; 151 } 152 153 154 pp::Var ScriptablePlugin::GetProperty(const pp::Var& name, 155 pp::Var* exception) { 156 PLUGIN_PRINTF(("ScriptablePlugin::GetProperty (name=%s)\n", 157 name.DebugString().c_str())); 158 if (plugin_ == NULL) { 159 return pp::Var(); 160 } 161 // Get the property. 162 NaClSrpcArg prop_value; 163 nacl::string prop_name = NameAsString(name); 164 if (!plugin_->GetProperty(prop_name, &prop_value)) { 165 return Error(prop_name, "GetProperty", "invocation failed", exception); 166 } 167 PLUGIN_PRINTF(("ScriptablePlugin::GetProperty (invocation done)\n")); 168 // Marshall output parameter. 169 pp::Var property = NaClSrpcArgToPPVar(&prop_value, exception); 170 if (!exception->is_undefined()) { 171 return Error(prop_name, "GetProperty", "output marshalling failed", 172 exception); 173 } 174 PLUGIN_PRINTF(("ScriptablePlugin::GetProperty (property=%s)\n", 175 property.DebugString().c_str())); 176 return property; 177 } 178 179 180 void ScriptablePlugin::SetProperty(const pp::Var& name, 181 const pp::Var& value, 182 pp::Var* exception) { 183 PLUGIN_PRINTF(("ScriptablePlugin::SetProperty (name=%s, value=%s)\n", 184 name.DebugString().c_str(), value.DebugString().c_str())); 185 Error("SetProperty", name.DebugString().c_str(), 186 "property setting is not supported", exception); 187 } 188 189 190 void ScriptablePlugin::RemoveProperty(const pp::Var& name, 191 pp::Var* exception) { 192 PLUGIN_PRINTF(("ScriptablePlugin::RemoveProperty (name=%s)\n", 193 name.DebugString().c_str())); 194 Error(NameAsString(name), "RemoveProperty", 195 "property removal is not supported", exception); 196 } 197 198 void ScriptablePlugin::GetAllPropertyNames(std::vector<pp::Var>* properties, 199 pp::Var* exception) { 200 PLUGIN_PRINTF(("ScriptablePlugin::GetAllPropertyNames ()\n")); 201 UNREFERENCED_PARAMETER(properties); 202 UNREFERENCED_PARAMETER(exception); 203 Error("GetAllPropertyNames", "", "GetAllPropertyNames is not supported", 204 exception); 205 } 206 207 208 pp::Var ScriptablePlugin::Call(const pp::Var& name, 209 const std::vector<pp::Var>& args, 210 pp::Var* exception) { 211 PLUGIN_PRINTF(("ScriptablePlugin::Call (name=%s, %" NACL_PRIuS 212 " args)\n", name.DebugString().c_str(), args.size())); 213 return Error("Call", name.DebugString().c_str(), 214 "method invocation is not supported", exception); 215 } 216 217 218 pp::Var ScriptablePlugin::Construct(const std::vector<pp::Var>& args, 219 pp::Var* exception) { 220 PLUGIN_PRINTF(("ScriptablePlugin::Construct (%" NACL_PRIuS 221 " args)\n", args.size())); 222 return Error("constructor", "Construct", "constructor is not supported", 223 exception); 224 } 225 226 227 ScriptablePlugin* ScriptablePlugin::AddRef() { 228 // This is called when we are about to share this object with the browser, 229 // and we need to make sure we have an internal plugin reference, so this 230 // object doesn't get deallocated when the browser discards its references. 231 if (var_ == NULL) { 232 var_ = new pp::VarPrivate(plugin_, this); 233 CHECK(var_ != NULL); 234 } 235 PLUGIN_PRINTF(("ScriptablePlugin::AddRef (this=%p, var=%p)\n", 236 static_cast<void*>(this), static_cast<void*>(var_))); 237 return this; 238 } 239 240 241 void ScriptablePlugin::Unref() { 242 // We should have no more than one internal owner of this object, so this 243 // should be called no more than once. 244 CHECK(++num_unref_calls_ == 1); 245 PLUGIN_PRINTF(("ScriptablePlugin::Unref (this=%p, var=%p)\n", 246 static_cast<void*>(this), static_cast<void*>(var_))); 247 if (var_ != NULL) { 248 // We have shared this with the browser while keeping our own var 249 // reference, but we no longer need ours. If the browser has copies, 250 // it will clean things up later, otherwise this object will get 251 // deallocated right away. 252 PLUGIN_PRINTF(("ScriptablePlugin::Unref (delete var)\n")); 253 pp::Var* var = var_; 254 var_ = NULL; 255 delete var; 256 } else { 257 // Neither the browser nor plugin ever var referenced this object, 258 // so it can safely discarded. 259 PLUGIN_PRINTF(("ScriptablePlugin::Unref (delete this)\n")); 260 CHECK(var_ == NULL); 261 delete this; 262 } 263 } 264 265 266 } // namespace plugin 267