Update Chrome plugin naming, cleanup leftover garbage, commit object freeing code that was never committed. This was originally committed to the changes/jat/single-xpi branch by mistake. Patch by: jat Review by: rice (TBR) git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@6779 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/plugins/npapi/LocalObjectTable.h b/plugins/npapi/LocalObjectTable.h index 9ff809d..7d95509 100644 --- a/plugins/npapi/LocalObjectTable.h +++ b/plugins/npapi/LocalObjectTable.h
@@ -16,8 +16,7 @@ * the License. */ -#include <vector> -#include <algorithm> +#include <map> #include "Debug.h" @@ -25,27 +24,21 @@ class LocalObjectTable { private: - static const int INITIAL_OBJECT_TABLE_SIZE = 300; + typedef std::map<int, NPObject*> ObjectMap; - int nextFree; - std::vector<NPObject*> objects; + int nextId; + ObjectMap objects; bool dontFree; - bool isFree(int id) { - // low bit is set for free pointers, object pointers can't be odd - NPObject* obj = objects[id]; - return !obj || (reinterpret_cast<long long>(obj) & 1); - } - void setFree(int id) { - objects[id] = reinterpret_cast<NPObject*>((nextFree << 1) | 1LL); - nextFree = id; + if (objects.erase(id) != 1) { + Debug::log(Debug::Error) << "setFree(id=" << id << "): object not in table" + << Debug::flush; + } } public: LocalObjectTable() { - nextFree = -1; - objects.reserve(INITIAL_OBJECT_TABLE_SIZE); dontFree = false; } @@ -55,64 +48,51 @@ * Add a new object, which must not be in the table, and return a new id for it. */ int add(NPObject* obj) { - int id; - if (nextFree >= 0) { - id = nextFree; - nextFree = int(reinterpret_cast<long long>(objects[nextFree])) >> 1; - objects[id] = obj; - } else { - id = static_cast<int>(objects.size()); - objects.push_back(obj); - } - Debug::log(Debug::Spam) << "LocalObjectTable::add(obj=" << obj << "): id=" << id - << Debug::flush; - // keep track that we hold a reference in the table - NPN_RetainObject(obj); + int id = nextId++; + set(id, obj); return id; } + void set(int id, NPObject* obj) { + Debug::log(Debug::Info) << "LocalObjectTable::set(id=" << id << ",obj=" << (void*)obj + << ")" << Debug::flush; + objects[id] = obj; + // keep track that we hold a reference in the table + NPN_RetainObject(obj); + } + void free(int id) { - Debug::log(Debug::Spam) << "LocalObjectTable::free(id=" << id << ")" << Debug::flush; - if (unsigned(id) >= objects.size()) { - Debug::log(Debug::Error) << "LocalObjectTable::free(id=" << id << "): invalid index (size=" - << objects.size() << Debug::flush; - return; - } - if (isFree(id)) { + Debug::log(Debug::Info) << "LocalObjectTable::free(id=" << id << ")" << Debug::flush; + ObjectMap::iterator it = objects.find(id); + if (it == objects.end()) { Debug::log(Debug::Error) << "Freeing freed object slot " << id << Debug::flush; return; } - NPObject* obj = objects[id]; setFree(id); if (!dontFree) { + NPObject* obj = it->second; NPN_ReleaseObject(obj); } } void freeAll() { - Debug::log(Debug::Spam) << "LocalObjectTable::freeAll()" << Debug::flush; - for (unsigned i = 0; i < objects.size(); ++i) { - if (!isFree(i)) { - NPObject* obj = objects[i]; - setFree(i); - if (!dontFree) { - NPN_ReleaseObject(obj); - } + Debug::log(Debug::Info) << "LocalObjectTable::freeAll()" << Debug::flush; + for (ObjectMap::const_iterator it = objects.begin(); it != objects.end(); ++it) { + NPObject* obj = it->second; + if (!dontFree) { + NPN_ReleaseObject(obj); } } + objects.clear(); } NPObject* get(int id) { - if (unsigned(id) >= objects.size()) { - Debug::log(Debug::Error) << "LocalObjectTable::get(id=" << id << "): invalid index (size=" - << objects.size() << Debug::flush; - return 0; + ObjectMap::iterator it = objects.find(id); + if (it == objects.end()) { + Debug::log(Debug::Error) << "LocalObjectTable::get(id=" << id + << "): no object found" << Debug::flush; } - if (isFree(id)) { - Debug::log(Debug::Error) << "Getting freed object slot " << id << Debug::flush; - return 0; - } - return objects[id]; + return it->second; } void setDontFree(bool dontFree) {
diff --git a/plugins/npapi/ScriptableInstance.cpp b/plugins/npapi/ScriptableInstance.cpp index 6a137bd..6149ffc 100644 --- a/plugins/npapi/ScriptableInstance.cpp +++ b/plugins/npapi/ScriptableInstance.cpp
@@ -1,276 +1,276 @@ -/* - * Copyright 2008 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -#include <cstring> - -#include "ScriptableInstance.h" -#include "InvokeMessage.h" -#include "ReturnMessage.h" -#include "ServerMethods.h" -#include "AllowedConnections.h" -#include "Preferences.h" -#include "AllowDialog.h" - -#include "mozincludes.h" -#include "scoped_ptr/scoped_ptr.h" -#include "NPVariantWrapper.h" - -using std::string; -using std::endl; - -static inline string convertToString(const NPString& str) { - return string(GetNPStringUTF8Characters(str), GetNPStringUTF8Length(str)); -} - -string ScriptableInstance::computeTabIdentity() { - return ""; -} - -void ScriptableInstance::dumpObjectBytes(NPObject* obj) { - char buf[20]; - Debug::log(Debug::Debugging) << " object bytes:\n"; - const unsigned char* ptr = reinterpret_cast<const unsigned char*>(obj); - for (int i = 0; i < 24; ++i) { - snprintf(buf, sizeof(buf), " %02x", ptr[i]); - Debug::log(Debug::Debugging) << buf; - } - NPVariant objVar; - OBJECT_TO_NPVARIANT(obj, objVar); - Debug::log(Debug::Debugging) << " obj.toString()=" - << NPVariantProxy::toString(objVar) << Debug::flush; -} - -ScriptableInstance::ScriptableInstance(NPP npp) : NPObjectWrapper<ScriptableInstance>(npp), - plugin(*reinterpret_cast<Plugin*>(npp->pdata)), - _channel(new HostChannel()), - localObjects(), - _connectId(NPN_GetStringIdentifier("connect")), - initID(NPN_GetStringIdentifier("init")), - toStringID(NPN_GetStringIdentifier("toString")), - connectedID(NPN_GetStringIdentifier("connected")), - statsID(NPN_GetStringIdentifier("stats")), - gwtId(NPN_GetStringIdentifier("__gwt_ObjectId")), - jsInvokeID(NPN_GetStringIdentifier("__gwt_jsInvoke")), - jsResultID(NPN_GetStringIdentifier("__gwt_makeResult")), - jsTearOffID(NPN_GetStringIdentifier("__gwt_makeTearOff")), - jsValueOfID(NPN_GetStringIdentifier("valueOf")), - idx0(NPN_GetIntIdentifier(0)), - idx1(NPN_GetIntIdentifier(1)) { - savedValueIdx = -1; - if (NPN_GetValue(npp, NPNVWindowNPObject, &window) != NPERR_NO_ERROR) { - Debug::log(Debug::Error) << "Error getting window object" << Debug::flush; - } -} - -ScriptableInstance::~ScriptableInstance() { - // TODO(jat): free any remaining Java objects held by JS, then make - // the JS wrapper handle that situation gracefully - if (window) { - NPN_ReleaseObject(window); - } - for (hash_map<int, JavaObject*>::iterator it = javaObjects.begin(); it != javaObjects.end(); - ++it) { - Debug::log(Debug::Spam) << " disconnecting Java wrapper " << it->first << Debug::flush; - it->second->disconnectPlugin(); - } - if (_channel) { - _channel->disconnectFromHost(); - delete _channel; - } -} - -void ScriptableInstance::dumpJSresult(const char* js) { - NPString npScript; - dupString(js, npScript); - NPVariantWrapper wrappedRetVal(*this); - if (!NPN_Evaluate(getNPP(), window, &npScript, wrappedRetVal.addressForReturn())) { - Debug::log(Debug::Error) << " *** dumpJSresult failed" << Debug::flush; - return; - } - Debug::log(Debug::Info) << "dumpWindow=" << wrappedRetVal.toString() << Debug::flush; -} - -bool ScriptableInstance::tryGetStringPrimitive(NPObject* obj, NPVariant& result) { - if (NPN_HasMethod(getNPP(), obj, jsValueOfID)) { - if (NPN_Invoke(getNPP(), obj, jsValueOfID, 0, 0, &result) - && NPVariantProxy::isString(result)) { - return true; - } - NPVariantProxy::release(result); - } - return false; -} - -bool ScriptableInstance::makeResult(bool isException, const Value& value, NPVariant* result) { - Debug::log(Debug::Debugging) << "makeResult(" << isException << ", " << value << ")" - << Debug::flush; - Value temp; - if (value.getType() == Value::JAVA_OBJECT) { - int javaId = value.getJavaObjectId(); - // We may have previously released the proxy for the same object id, - // but have not yet sent a free message back to the server. - javaObjectsToFree.erase(javaId); - } - NPVariantArray varArgs(*this, 3); - varArgs[0] = isException ? 1 : 0; - varArgs[1] = value; - NPVariantWrapper retVal(*this); - return NPN_Invoke(getNPP(), window, jsResultID, varArgs.getArray(), varArgs.getSize(), result); -} - -//===================================================================================== -// NPObject methods -//===================================================================================== - -bool ScriptableInstance::hasProperty(NPIdentifier name) { - if (!NPN_IdentifierIsString(name)) { - // all numeric properties are ok, as we assume only JSNI code is making - // the field access via dispatchID - return true; - } - // TODO: special-case toString tear-offs - return name == statsID || name == connectedID; -} - -bool ScriptableInstance::getProperty(NPIdentifier name, NPVariant* variant) { - Debug::log(Debug::Debugging) << "ScriptableInstance::getProperty(name=" - << NPN_UTF8FromIdentifier(name) << ")" << Debug::flush; - bool retVal = false; - VOID_TO_NPVARIANT(*variant); - if (name == connectedID) { - BOOLEAN_TO_NPVARIANT(_channel->isConnected(), *variant); - retVal = true; - } else if (name == statsID) { - NPVariantProxy::assignFrom(*variant, "<stats data>"); - retVal = true; - } - if (retVal) { - // TODO: testing - Debug::log(Debug::Debugging) << " return value " << *variant - << Debug::flush; - } - return retVal; -} - -bool ScriptableInstance::setProperty(NPIdentifier name, const NPVariant* variant) { - Debug::log(Debug::Debugging) << "ScriptableInstance::setProperty(name=" - << NPN_UTF8FromIdentifier(name) << ", value=" << *variant << ")" - << Debug::flush; - return false; -} - -bool ScriptableInstance::hasMethod(NPIdentifier name) { - Debug::log(Debug::Debugging) << "ScriptableInstance::hasMethod(name=" << NPN_UTF8FromIdentifier(name) << ")" - << Debug::flush; - if (name == _connectId || name == initID || name == toStringID) { - return true; - } - return false; -} - -bool ScriptableInstance::invoke(NPIdentifier name, const NPVariant* args, unsigned argCount, - NPVariant* result) { - NPUTF8* uname = NPN_UTF8FromIdentifier(name); - Debug::log(Debug::Debugging) << "ScriptableInstance::invoke(name=" << uname << ",#args=" << argCount << ")" - << Debug::flush; - VOID_TO_NPVARIANT(*result); - if (name == _connectId) { - connect(args, argCount, result); - } else if (name == initID) { - init(args, argCount, result); - } else if (name == toStringID) { - // TODO(jat): figure out why this doesn't show in Firebug - string val("[GWT OOPHM Plugin: connected="); - val += _channel->isConnected() ? 'Y' : 'N'; - val += ']'; - NPVariantProxy::assignFrom(*result, val); - } - return true; -} - -bool ScriptableInstance::invokeDefault(const NPVariant* args, unsigned argCount, - NPVariant* result) { - Debug::log(Debug::Debugging) << "ScriptableInstance::invokeDefault(#args=" << argCount << ")" - << Debug::flush; - VOID_TO_NPVARIANT(*result); - return true; -} - -bool ScriptableInstance::enumeration(NPIdentifier** propReturn, uint32_t* count) { - Debug::log(Debug::Debugging) << "ScriptableInstance::enumeration()" << Debug::flush; - int n = 2; - NPIdentifier* props = static_cast<NPIdentifier*>(NPN_MemAlloc(sizeof(NPIdentifier) * n)); - props[0] = connectedID; - props[1] = statsID; - *propReturn = props; - *count = n; - return true; -} - -//===================================================================================== -// internal methods -//===================================================================================== - -void ScriptableInstance::init(const NPVariant* args, unsigned argCount, NPVariant* result) { - if (argCount != 1 || !NPVariantProxy::isObject(args[0])) { - // TODO: better failure? - Debug::log(Debug::Error) << "ScriptableInstance::init called with incorrect arguments:\n"; - for (unsigned i = 0; i < argCount; ++i) { - Debug::log(Debug::Error) << " " << i << " " << NPVariantProxy::toString(args[i]) << "\n"; - } - Debug::log(Debug::Error) << Debug::flush; - result->type = NPVariantType_Void; - return; - } - if (window) { - NPN_ReleaseObject(window); - } - // replace our window object with that passed by the caller - window = NPVariantProxy::getAsObject(args[0]); - NPN_RetainObject(window); - BOOLEAN_TO_NPVARIANT(true, *result); - result->type = NPVariantType_Bool; -} - -void ScriptableInstance::connect(const NPVariant* args, unsigned argCount, NPVariant* result) { - if (argCount != 5 || !NPVariantProxy::isString(args[0]) - || !NPVariantProxy::isString(args[1]) - || !NPVariantProxy::isString(args[2]) - || !NPVariantProxy::isString(args[3]) - || !NPVariantProxy::isString(args[4])) { - // TODO: better failure? - Debug::log(Debug::Error) << "ScriptableInstance::connect called with incorrect arguments:\n"; - for (unsigned i = 0; i < argCount; ++i) { - Debug::log(Debug::Error) << " " << i << " " << NPVariantProxy::toString(args[i]) << "\n"; - } - Debug::log(Debug::Error) << Debug::flush; - result->type = NPVariantType_Void; - return; - } - const NPString url = args[0].value.stringValue; - const NPString sessionKey = args[1].value.stringValue; - const NPString hostAddr = args[2].value.stringValue; - const NPString moduleName = args[3].value.stringValue; - const NPString hostedHtmlVersion = args[4].value.stringValue; - Debug::log(Debug::Info) << "ScriptableInstance::connect(url=" << NPVariantProxy::toString(args[0]) - << ",sessionKey=" << NPVariantProxy::toString(args[1]) << ",host=" << NPVariantProxy::toString(args[2]) - << ",module=" << NPVariantProxy::toString(args[3]) << ",hostedHtmlVers=" << NPVariantProxy::toString(args[4]) - << ")" << Debug::flush; - const std::string urlStr = convertToString(url); - +/* + * Copyright 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +#include <cstring> + +#include "ScriptableInstance.h" +#include "InvokeMessage.h" +#include "ReturnMessage.h" +#include "ServerMethods.h" +#include "AllowedConnections.h" +#include "Preferences.h" +#include "AllowDialog.h" + +#include "mozincludes.h" +#include "scoped_ptr/scoped_ptr.h" +#include "NPVariantWrapper.h" + +using std::string; +using std::endl; + +static inline string convertToString(const NPString& str) { + return string(GetNPStringUTF8Characters(str), GetNPStringUTF8Length(str)); +} + +string ScriptableInstance::computeTabIdentity() { + return ""; +} + +void ScriptableInstance::dumpObjectBytes(NPObject* obj) { + char buf[20]; + Debug::log(Debug::Debugging) << " object bytes:\n"; + const unsigned char* ptr = reinterpret_cast<const unsigned char*>(obj); + for (int i = 0; i < 24; ++i) { + snprintf(buf, sizeof(buf), " %02x", ptr[i]); + Debug::log(Debug::Debugging) << buf; + } + NPVariant objVar; + OBJECT_TO_NPVARIANT(obj, objVar); + Debug::log(Debug::Debugging) << " obj.toString()=" + << NPVariantProxy::toString(objVar) << Debug::flush; +} + +ScriptableInstance::ScriptableInstance(NPP npp) : NPObjectWrapper<ScriptableInstance>(npp), + plugin(*reinterpret_cast<Plugin*>(npp->pdata)), + _channel(new HostChannel()), + localObjects(), + _connectId(NPN_GetStringIdentifier("connect")), + initID(NPN_GetStringIdentifier("init")), + toStringID(NPN_GetStringIdentifier("toString")), + connectedID(NPN_GetStringIdentifier("connected")), + statsID(NPN_GetStringIdentifier("stats")), + gwtId(NPN_GetStringIdentifier("__gwt_ObjectId")), + jsInvokeID(NPN_GetStringIdentifier("__gwt_jsInvoke")), + jsResultID(NPN_GetStringIdentifier("__gwt_makeResult")), + jsTearOffID(NPN_GetStringIdentifier("__gwt_makeTearOff")), + jsValueOfID(NPN_GetStringIdentifier("valueOf")), + idx0(NPN_GetIntIdentifier(0)), + idx1(NPN_GetIntIdentifier(1)) { + savedValueIdx = -1; + if (NPN_GetValue(npp, NPNVWindowNPObject, &window) != NPERR_NO_ERROR) { + Debug::log(Debug::Error) << "Error getting window object" << Debug::flush; + } +} + +ScriptableInstance::~ScriptableInstance() { + // TODO(jat): free any remaining Java objects held by JS, then make + // the JS wrapper handle that situation gracefully + if (window) { + NPN_ReleaseObject(window); + } + for (hash_map<int, JavaObject*>::iterator it = javaObjects.begin(); it != javaObjects.end(); + ++it) { + Debug::log(Debug::Spam) << " disconnecting Java wrapper " << it->first << Debug::flush; + it->second->disconnectPlugin(); + } + if (_channel) { + _channel->disconnectFromHost(); + delete _channel; + } +} + +void ScriptableInstance::dumpJSresult(const char* js) { + NPString npScript; + dupString(js, npScript); + NPVariantWrapper wrappedRetVal(*this); + if (!NPN_Evaluate(getNPP(), window, &npScript, wrappedRetVal.addressForReturn())) { + Debug::log(Debug::Error) << " *** dumpJSresult failed" << Debug::flush; + return; + } + Debug::log(Debug::Info) << "dumpWindow=" << wrappedRetVal.toString() << Debug::flush; +} + +bool ScriptableInstance::tryGetStringPrimitive(NPObject* obj, NPVariant& result) { + if (NPN_HasMethod(getNPP(), obj, jsValueOfID)) { + if (NPN_Invoke(getNPP(), obj, jsValueOfID, 0, 0, &result) + && NPVariantProxy::isString(result)) { + return true; + } + NPVariantProxy::release(result); + } + return false; +} + +bool ScriptableInstance::makeResult(bool isException, const Value& value, NPVariant* result) { + Debug::log(Debug::Debugging) << "makeResult(" << isException << ", " << value << ")" + << Debug::flush; + Value temp; + if (value.getType() == Value::JAVA_OBJECT) { + int javaId = value.getJavaObjectId(); + // We may have previously released the proxy for the same object id, + // but have not yet sent a free message back to the server. + javaObjectsToFree.erase(javaId); + } + NPVariantArray varArgs(*this, 3); + varArgs[0] = isException ? 1 : 0; + varArgs[1] = value; + NPVariantWrapper retVal(*this); + return NPN_Invoke(getNPP(), window, jsResultID, varArgs.getArray(), varArgs.getSize(), result); +} + +//============================================================================= +// NPObject methods +//============================================================================= + +bool ScriptableInstance::hasProperty(NPIdentifier name) { + if (!NPN_IdentifierIsString(name)) { + // all numeric properties are ok, as we assume only JSNI code is making + // the field access via dispatchID + return true; + } + // TODO: special-case toString tear-offs + return name == statsID || name == connectedID; +} + +bool ScriptableInstance::getProperty(NPIdentifier name, NPVariant* variant) { + Debug::log(Debug::Debugging) << "ScriptableInstance::getProperty(name=" + << NPN_UTF8FromIdentifier(name) << ")" << Debug::flush; + bool retVal = false; + VOID_TO_NPVARIANT(*variant); + if (name == connectedID) { + BOOLEAN_TO_NPVARIANT(_channel->isConnected(), *variant); + retVal = true; + } else if (name == statsID) { + NPVariantProxy::assignFrom(*variant, "<stats data>"); + retVal = true; + } + if (retVal) { + // TODO: testing + Debug::log(Debug::Debugging) << " return value " << *variant + << Debug::flush; + } + return retVal; +} + +bool ScriptableInstance::setProperty(NPIdentifier name, const NPVariant* variant) { + Debug::log(Debug::Debugging) << "ScriptableInstance::setProperty(name=" + << NPN_UTF8FromIdentifier(name) << ", value=" << *variant << ")" + << Debug::flush; + return false; +} + +bool ScriptableInstance::hasMethod(NPIdentifier name) { + Debug::log(Debug::Debugging) << "ScriptableInstance::hasMethod(name=" << NPN_UTF8FromIdentifier(name) << ")" + << Debug::flush; + if (name == _connectId || name == initID || name == toStringID) { + return true; + } + return false; +} + +bool ScriptableInstance::invoke(NPIdentifier name, const NPVariant* args, unsigned argCount, + NPVariant* result) { + NPUTF8* uname = NPN_UTF8FromIdentifier(name); + Debug::log(Debug::Debugging) << "ScriptableInstance::invoke(name=" << uname << ",#args=" << argCount << ")" + << Debug::flush; + VOID_TO_NPVARIANT(*result); + if (name == _connectId) { + connect(args, argCount, result); + } else if (name == initID) { + init(args, argCount, result); + } else if (name == toStringID) { + // TODO(jat): figure out why this doesn't show in Firebug + string val("[GWT OOPHM Plugin: connected="); + val += _channel->isConnected() ? 'Y' : 'N'; + val += ']'; + NPVariantProxy::assignFrom(*result, val); + } + return true; +} + +bool ScriptableInstance::invokeDefault(const NPVariant* args, unsigned argCount, + NPVariant* result) { + Debug::log(Debug::Debugging) << "ScriptableInstance::invokeDefault(#args=" << argCount << ")" + << Debug::flush; + VOID_TO_NPVARIANT(*result); + return true; +} + +bool ScriptableInstance::enumeration(NPIdentifier** propReturn, uint32_t* count) { + Debug::log(Debug::Debugging) << "ScriptableInstance::enumeration()" << Debug::flush; + int n = 2; + NPIdentifier* props = static_cast<NPIdentifier*>(NPN_MemAlloc(sizeof(NPIdentifier) * n)); + props[0] = connectedID; + props[1] = statsID; + *propReturn = props; + *count = n; + return true; +} + +//============================================================================= +// internal methods +//============================================================================= + +void ScriptableInstance::init(const NPVariant* args, unsigned argCount, NPVariant* result) { + if (argCount != 1 || !NPVariantProxy::isObject(args[0])) { + // TODO: better failure? + Debug::log(Debug::Error) << "ScriptableInstance::init called with incorrect arguments:\n"; + for (unsigned i = 0; i < argCount; ++i) { + Debug::log(Debug::Error) << " " << i << " " << NPVariantProxy::toString(args[i]) << "\n"; + } + Debug::log(Debug::Error) << Debug::flush; + result->type = NPVariantType_Void; + return; + } + if (window) { + NPN_ReleaseObject(window); + } + // replace our window object with that passed by the caller + window = NPVariantProxy::getAsObject(args[0]); + NPN_RetainObject(window); + BOOLEAN_TO_NPVARIANT(true, *result); + result->type = NPVariantType_Bool; +} + +void ScriptableInstance::connect(const NPVariant* args, unsigned argCount, NPVariant* result) { + if (argCount != 5 || !NPVariantProxy::isString(args[0]) + || !NPVariantProxy::isString(args[1]) + || !NPVariantProxy::isString(args[2]) + || !NPVariantProxy::isString(args[3]) + || !NPVariantProxy::isString(args[4])) { + // TODO: better failure? + Debug::log(Debug::Error) << "ScriptableInstance::connect called with incorrect arguments:\n"; + for (unsigned i = 0; i < argCount; ++i) { + Debug::log(Debug::Error) << " " << i << " " << NPVariantProxy::toString(args[i]) << "\n"; + } + Debug::log(Debug::Error) << Debug::flush; + result->type = NPVariantType_Void; + return; + } + const NPString url = args[0].value.stringValue; + const NPString sessionKey = args[1].value.stringValue; + const NPString hostAddr = args[2].value.stringValue; + const NPString moduleName = args[3].value.stringValue; + const NPString hostedHtmlVersion = args[4].value.stringValue; + Debug::log(Debug::Info) << "ScriptableInstance::connect(url=" << NPVariantProxy::toString(args[0]) + << ",sessionKey=" << NPVariantProxy::toString(args[1]) << ",host=" << NPVariantProxy::toString(args[2]) + << ",module=" << NPVariantProxy::toString(args[3]) << ",hostedHtmlVers=" << NPVariantProxy::toString(args[4]) + << ")" << Debug::flush; + const std::string urlStr = convertToString(url); + Preferences::loadAccessList(); bool allowed = false; if (!AllowedConnections::matchesRule(urlStr, &allowed)) { @@ -281,387 +281,388 @@ Preferences::addNewRule(host, !allowed); } } - if (!allowed) { - BOOLEAN_TO_NPVARIANT(false, *result); - result->type = NPVariantType_Bool; - return; - } - - bool connected = false; - unsigned port = 9997; // TODO(jat): should there be a default? - int n = GetNPStringUTF8Length(hostAddr); - scoped_ptr<char> host(new char[n + 1]); - const char* s = GetNPStringUTF8Characters(hostAddr); - char* d = host.get(); - while (n > 0 && *s != ':') { - n--; - *d++ = *s++; - } - *d = 0; - if (n > 0) { - port = atoi(s + 1); - } - Debug::log(Debug::Info) << " host=" << host.get() << ",port=" << port << Debug::flush; - - - if (!_channel->connectToHost(host.get(), port)) { - BOOLEAN_TO_NPVARIANT(false, *result); - result->type = NPVariantType_Bool; - } - - string hostedHtmlVersionStr = convertToString(hostedHtmlVersion); - if (!_channel->init(this, BROWSERCHANNEL_PROTOCOL_VERSION, - BROWSERCHANNEL_PROTOCOL_VERSION, hostedHtmlVersionStr)) { - BOOLEAN_TO_NPVARIANT(false, *result); - result->type = NPVariantType_Bool; - } - - string moduleNameStr = convertToString(moduleName); - string userAgent(NPN_UserAgent(getNPP())); - string tabKeyStr = computeTabIdentity(); - string sessionKeyStr = convertToString(sessionKey); - Debug::log(Debug::Debugging) << " connected, sending loadModule" << Debug::flush; - connected = LoadModuleMessage::send(*_channel, urlStr, tabKeyStr, sessionKeyStr, - moduleNameStr, userAgent, this); - BOOLEAN_TO_NPVARIANT(connected, *result); - result->type = NPVariantType_Bool; -} - -int ScriptableInstance::getLocalObjectRef(NPObject* obj) { - NPVariantWrapper wrappedRetVal(*this); - int id; - if (NPN_GetProperty(getNPP(), obj, gwtId, wrappedRetVal.addressForReturn()) - && wrappedRetVal.isInt()) { - id = wrappedRetVal.getAsInt(); - } else { - id = localObjects.add(obj); - wrappedRetVal = id; - if (!NPN_SetProperty(getNPP(), obj, gwtId, wrappedRetVal.address())) { - Debug::log(Debug::Error) << "Setting GWT id on object failed" << Debug::flush; - } - } - return id; -} - -void ScriptableInstance::fatalError(HostChannel& channel, const std::string& message) { - // TODO(jat): better error handling - Debug::log(Debug::Error) << "Fatal error: " << message << Debug::flush; -} - -void ScriptableInstance::dupString(const char* str, NPString& npString) { - npString.UTF8Length = static_cast<uint32_t>(strlen(str)); - NPUTF8* chars = static_cast<NPUTF8*>(NPN_MemAlloc(npString.UTF8Length)); - memcpy(chars, str, npString.UTF8Length); - npString.UTF8Characters = chars; -} - -// SessionHandler methods -void ScriptableInstance::freeValue(HostChannel& channel, int idCount, const int* const ids) { - Debug::log(Debug::Debugging) << "freeValue(#ids=" << idCount << ")" << Debug::flush; - for (int i = 0; i < idCount; ++i) { - Debug::log(Debug::Spam) << " id=" << ids[i] << Debug::flush; - NPObject* obj = localObjects.get(ids[i]); - if (!NPN_RemoveProperty(getNPP(), obj, gwtId)) { - Debug::log(Debug::Error) << "Unable to remove GWT ID from object " << ids[i] << Debug::flush; - } else { - localObjects.free(ids[i]); - } - } -} - -void ScriptableInstance::loadJsni(HostChannel& channel, const std::string& js) { - NPString npScript; - dupString(js.c_str(), npScript); - NPVariantWrapper npResult(*this); - Debug::log(Debug::Spam) << "loadJsni - \n" << js << Debug::flush; - if (!NPN_Evaluate(getNPP(), window, &npScript, npResult.addressForReturn())) { - Debug::log(Debug::Error) << "loadJsni failed\n" << js << Debug::flush; - } -} - -Value ScriptableInstance::clientMethod_getProperty(HostChannel& channel, int numArgs, const Value* const args) { - if (numArgs != 2 || !args[0].isInt() || (!args[1].isString() && !args[1].isInt())) { - Debug::log(Debug::Error) << "Incorrect invocation of getProperty: #args=" << numArgs << ":"; - for (int i = 0; i < numArgs; ++i) { - Debug::log(Debug::Error) << " " << i << "=" << args[i].toString(); - } - Debug::log(Debug::Error) << Debug::flush; - return Value(); - } - int id = args[0].getInt(); - NPObject* obj = localObjects.get(id); - NPIdentifier propID; - if (args[1].isString()) { - std::string propName = args[1].getString(); - propID = NPN_GetStringIdentifier(propName.c_str()); - } else { - int propNum = args[1].getInt(); - propID = NPN_GetIntIdentifier(propNum); - } - NPVariantWrapper npResult(*this); - if (!NPN_GetProperty(getNPP(), obj, propID, npResult.addressForReturn())) { - Debug::log(Debug::Warning) << "getProperty(id=" << id << ", prop=" - << NPN_UTF8FromIdentifier(propID) << ") failed" << Debug::flush; - return Value(); - } - return npResult.getAsValue(*this); -} - -Value ScriptableInstance::clientMethod_setProperty(HostChannel& channel, int numArgs, const Value* const args) { - if (numArgs != 2 || !args[0].isInt() || (!args[1].isString() && !args[1].isInt())) { - Debug::log(Debug::Error) << "Incorrect invocation of setProperty: #args=" - << numArgs << ":"; - for (int i = 0; i < numArgs; ++i) { - Debug::log(Debug::Error) << " " << i << "=" << args[i].toString(); - } - Debug::log(Debug::Error) << Debug::flush; - return Value(); - } - int id = args[0].getInt(); - NPObject* obj = localObjects.get(id); - NPIdentifier propID; - if (args[1].isString()) { - std::string propName = args[1].getString(); - propID = NPN_GetStringIdentifier(propName.c_str()); - } else { - int propNum = args[1].getInt(); - propID = NPN_GetIntIdentifier(propNum); - } - NPVariantWrapper npValue(*this); - npValue.operator=(args[2]); - if (!NPN_SetProperty(getNPP(), obj, propID, npValue.address())) { - Debug::log(Debug::Warning) << "setProperty(id=" << id << ", prop=" - << NPN_UTF8FromIdentifier(propID) << ", val=" << args[2].toString() - << ") failed" << Debug::flush; - return Value(); - } - return Value(); -} - -/** - * SessionHandler.invoke - used by LoadModule and reactToMessages* to process server-side - * requests to invoke methods in Javascript or the plugin. - */ -bool ScriptableInstance::invokeSpecial(HostChannel& channel, SpecialMethodId dispatchId, - int numArgs, const Value* const args, Value* returnValue) { - switch (dispatchId) { - case SessionHandler::HasMethod: - case SessionHandler::HasProperty: - break; - case SessionHandler::SetProperty: - *returnValue = clientMethod_setProperty(channel, numArgs, args); - return false; - case SessionHandler::GetProperty: - *returnValue = clientMethod_getProperty(channel, numArgs, args); - return false; - default: - break; - } - Debug::log(Debug::Error) << "Unexpected special method " << dispatchId - << " called on plugin; #args=" << numArgs << ":"; - for (int i = 0; i < numArgs; ++i) { - Debug::log(Debug::Error) << " " << i << "=" << args[i].toString(); - } - Debug::log(Debug::Error) << Debug::flush; - // TODO(jat): should we create a real exception object? - std::string buf("unexpected invokeSpecial("); - buf += static_cast<int>(dispatchId); - buf += ")"; - returnValue->setString(buf); - return true; -} - -bool ScriptableInstance::invoke(HostChannel& channel, const Value& thisRef, - const std::string& methodName, int numArgs, const Value* const args, - Value* returnValue) { - Debug::log(Debug::Debugging) << "invokeJS(" << methodName << ", this=" - << thisRef.toString() << ", numArgs=" << numArgs << ")" << Debug::flush; - NPVariantArray varArgs(*this, numArgs + 2); - varArgs[0] = thisRef; - varArgs[1] = methodName; - for (int i = 0; i < numArgs; ++i) { - varArgs[i + 2] = args[i]; - } - const NPVariant* argArray = varArgs.getArray(); - if (Debug::level(Debug::Spam)) { - for (int i = 0; i < varArgs.getSize(); ++i) { - Debug::log(Debug::Spam) << " arg " << i << " is " - << NPVariantProxy::toString(argArray[i]) << Debug::flush; - } - } - NPVariantWrapper wrappedRetVal(*this); - if (!NPN_Invoke(getNPP(), window, jsInvokeID, argArray, varArgs.getSize(), - wrappedRetVal.addressForReturn())) { - Debug::log(Debug::Error) << "*** invokeJS(" << methodName << ", this=" - << thisRef.toString() << ", numArgs=" << numArgs << ") failed" - << Debug::flush; - // TODO(jat): should we create a real exception object? - returnValue->setString("invoke of " + methodName + " failed"); - return true; - } - Debug::log(Debug::Spam) << " wrapped return is " << wrappedRetVal.toString() << Debug::flush; - NPVariantWrapper exceptFlag(*this); - NPVariantWrapper retval(*this); - NPObject* wrappedArray = wrappedRetVal.getAsObject(); - if (!NPN_GetProperty(getNPP(), wrappedArray, idx0, exceptFlag.addressForReturn())) { - Debug::log(Debug::Error) << " Error getting element 0 of wrapped return value (" - << wrappedRetVal << ") on call to " << methodName << Debug::flush; - } - if (!NPN_GetProperty(getNPP(), wrappedArray, idx1, retval.addressForReturn())) { - Debug::log(Debug::Error) << " Error getting element 1 of wrapped return value (" - << wrappedRetVal << ") on call to " << methodName << Debug::flush; - } - Debug::log(Debug::Debugging) << " return value " << retval.toString() << Debug::flush; - *returnValue = retval.getAsValue(*this); - if (exceptFlag.isInt() && exceptFlag.getAsInt() != 0) { - Debug::log(Debug::Debugging) << " exception: " << retval << Debug::flush; - return true; - } - return false; -} - -bool ScriptableInstance::JavaObject_invoke(int objectId, int dispId, - const NPVariant* args, uint32_t numArgs, NPVariant* result) { - Debug::log(Debug::Debugging) << "JavaObject_invoke(dispId= " << dispId << ", numArgs=" << numArgs << ")" << Debug::flush; - if (Debug::level(Debug::Spam)) { - for (uint32_t i = 0; i < numArgs; ++i) { - Debug::log(Debug::Spam) << " " << i << " = " << args[i] << Debug::flush; - } - } - - bool isRawToString = false; - if (dispId == -1) { - dispId = 0; - isRawToString = true; - } - - Value javaThis; - javaThis.setJavaObject(objectId); - scoped_array<Value> vargs(new Value[numArgs]); - for (unsigned i = 0; i < numArgs; ++i) { - vargs[i] = NPVariantProxy::getAsValue(args[i], *this); - } - if (!InvokeMessage::send(*_channel, javaThis, dispId, numArgs, vargs.get())) { - Debug::log(Debug::Error) << "JavaObject_invoke: failed to send invoke message" << Debug::flush; - // TODO(jat): returning false here spams the browser console - return true; - } - Debug::log(Debug::Debugging) << " return from invoke" << Debug::flush; - scoped_ptr<ReturnMessage> retMsg(_channel->reactToMessagesWhileWaitingForReturn(this)); - if (!retMsg.get()) { - Debug::log(Debug::Error) << "JavaObject_invoke: failed to get return value" << Debug::flush; - return false; - } - if (isRawToString) { - // toString() needs the raw value - NPVariantProxy::assignFrom(*this, *result, retMsg->getReturnValue()); - return !retMsg->isException(); - } - // Wrap the result - return makeResult(retMsg->isException(), retMsg->getReturnValue(), result); -} - -bool ScriptableInstance::JavaObject_getProperty(int objectId, int dispId, - NPVariant* result) { - Debug::log(Debug::Debugging) << "JavaObject_getProperty(objectid=" - << objectId << ", dispId=" << dispId << ")" << Debug::flush; - VOID_TO_NPVARIANT(*result); - Value propertyValue = ServerMethods::getProperty(*_channel, this, objectId, dispId); - if (propertyValue.isJsObject()) { - // TODO(jat): special-case for testing - NPObject* npObj = localObjects.get(propertyValue.getJsObjectId()); - OBJECT_TO_NPVARIANT(npObj, *result); - NPN_RetainObject(npObj); - } else { - NPVariantProxy::assignFrom(*this, *result, propertyValue); - } - Debug::log(Debug::Debugging) << " return val=" << propertyValue - << ", NPVariant=" << *result << Debug::flush; - if (NPVariantProxy::isObject(*result)) { - dumpObjectBytes(NPVariantProxy::getAsObject(*result)); - } - if (NPVariantProxy::isObject(*result)) { - Debug::log(Debug::Debugging) << " final return refcount = " - << NPVariantProxy::getAsObject(*result)->referenceCount << Debug::flush; - } - return true; -} - -bool ScriptableInstance::JavaObject_setProperty(int objectId, int dispId, - const NPVariant* npValue) { - Debug::log(Debug::Debugging) << "JavaObject_setProperty(objectid=" - << objectId << ", dispId=" << dispId << ", value=" << *npValue << ")" << Debug::flush; - if (NPVariantProxy::isObject(*npValue)) { - Debug::log(Debug::Debugging) << " before localObj: refcount = " - << NPVariantProxy::getAsObject(*npValue)->referenceCount << Debug::flush; - } - Value value = NPVariantProxy::getAsValue(*npValue, *this, true); - if (NPVariantProxy::isObject(*npValue)) { - Debug::log(Debug::Debugging) << " after localObj: refcount = " - << NPVariantProxy::getAsObject(*npValue)->referenceCount << Debug::flush; - } - if (NPVariantProxy::isObject(*npValue)) { - dumpObjectBytes(NPVariantProxy::getAsObject(*npValue)); - } - Debug::log(Debug::Debugging) << " as value: " << value << Debug::flush; - // TODO: no way to set an actual exception object! (Could ClassCastException on server.) - return ServerMethods::setProperty(*_channel, this, objectId, dispId, value); -} - -bool ScriptableInstance::JavaObject_getToStringTearOff(NPVariant* result) { - Debug::log(Debug::Debugging) << "JavaObject_getToStringTearOff()" << Debug::flush; - VOID_TO_NPVARIANT(*result); - - Value temp; - NPVariantArray varArgs(*this, 3); - temp.setNull(); varArgs[0] = temp; // proxy: no proxy needed - temp.setInt(0); varArgs[1] = temp; // dispId: always 0 for toString() - temp.setInt(0); varArgs[2] = temp; // argCount: always 0 for toString() - - if (!NPN_Invoke(getNPP(), window, jsTearOffID, varArgs.getArray(), 3, result)) { - Debug::log(Debug::Error) << "*** JavaObject_getToStringTearOff() failed" - << Debug::flush; - return true; - } - return true; -} - -JavaObject* ScriptableInstance::createJavaWrapper(int objectId) { - Debug::log(Debug::Debugging) << "createJavaWrapper(objectId=" << objectId << ")" << Debug::flush; - JavaObject* jObj; - hash_map<int, JavaObject*>::iterator it = javaObjects.find(objectId); - if (it != javaObjects.end()) { - jObj = it->second; - NPN_RetainObject(jObj); - return jObj; - } - jObj = JavaObject::create(this, objectId); - javaObjects[objectId] = jObj; - return jObj; -} - -void ScriptableInstance::destroyJavaWrapper(JavaObject* jObj) { - int objectId = jObj->getObjectId(); - if (!javaObjects.erase(objectId)) { - Debug::log(Debug::Error) << "destroyJavaWrapper(id=" << objectId - << "): trying to free unknown JavaObject" << Debug::flush; - } - Debug::log(Debug::Debugging) << "destroyJavaWrapper(id=" << objectId << ")" << Debug::flush; - javaObjectsToFree.insert(objectId); -} - -void ScriptableInstance::sendFreeValues(HostChannel& channel) { - unsigned n = javaObjectsToFree.size(); - if (n) { - scoped_array<int> ids(new int[n]); - int i = 0; - for (std::set<int>::iterator it = javaObjectsToFree.begin(); - it != javaObjectsToFree.end(); ++it) { - ids[i++] = *it; - } - if (ServerMethods::freeJava(channel, this, n, ids.get())) { - javaObjectsToFree.clear(); - } - } -} - + if (!allowed) { + BOOLEAN_TO_NPVARIANT(false, *result); + result->type = NPVariantType_Bool; + return; + } + + bool connected = false; + unsigned port = 9997; // TODO(jat): should there be a default? + int n = GetNPStringUTF8Length(hostAddr); + scoped_ptr<char> host(new char[n + 1]); + const char* s = GetNPStringUTF8Characters(hostAddr); + char* d = host.get(); + while (n > 0 && *s != ':') { + n--; + *d++ = *s++; + } + *d = 0; + if (n > 0) { + port = atoi(s + 1); + } + Debug::log(Debug::Info) << " host=" << host.get() << ",port=" << port << Debug::flush; + + + if (!_channel->connectToHost(host.get(), port)) { + BOOLEAN_TO_NPVARIANT(false, *result); + result->type = NPVariantType_Bool; + } + + string hostedHtmlVersionStr = convertToString(hostedHtmlVersion); + if (!_channel->init(this, BROWSERCHANNEL_PROTOCOL_VERSION, + BROWSERCHANNEL_PROTOCOL_VERSION, hostedHtmlVersionStr)) { + BOOLEAN_TO_NPVARIANT(false, *result); + result->type = NPVariantType_Bool; + } + + string moduleNameStr = convertToString(moduleName); + string userAgent(NPN_UserAgent(getNPP())); + string tabKeyStr = computeTabIdentity(); + string sessionKeyStr = convertToString(sessionKey); + Debug::log(Debug::Debugging) << " connected, sending loadModule" << Debug::flush; + connected = LoadModuleMessage::send(*_channel, urlStr, tabKeyStr, sessionKeyStr, + moduleNameStr, userAgent, this); + BOOLEAN_TO_NPVARIANT(connected, *result); + result->type = NPVariantType_Bool; +} + +int ScriptableInstance::getLocalObjectRef(NPObject* obj) { + NPVariantWrapper wrappedRetVal(*this); + int id; + if (NPN_GetProperty(getNPP(), obj, gwtId, wrappedRetVal.addressForReturn()) + && wrappedRetVal.isInt()) { + id = wrappedRetVal.getAsInt(); + localObjects.set(id, obj); + } else { + id = localObjects.add(obj); + wrappedRetVal = id; + if (!NPN_SetProperty(getNPP(), obj, gwtId, wrappedRetVal.address())) { + Debug::log(Debug::Error) << "Setting GWT id on object failed" << Debug::flush; + } + } + return id; +} + +void ScriptableInstance::fatalError(HostChannel& channel, const std::string& message) { + // TODO(jat): better error handling + Debug::log(Debug::Error) << "Fatal error: " << message << Debug::flush; +} + +void ScriptableInstance::dupString(const char* str, NPString& npString) { + npString.UTF8Length = static_cast<uint32_t>(strlen(str)); + NPUTF8* chars = static_cast<NPUTF8*>(NPN_MemAlloc(npString.UTF8Length)); + memcpy(chars, str, npString.UTF8Length); + npString.UTF8Characters = chars; +} + +// SessionHandler methods +void ScriptableInstance::freeValue(HostChannel& channel, int idCount, const int* const ids) { + Debug::log(Debug::Debugging) << "freeValue(#ids=" << idCount << ")" << Debug::flush; + for (int i = 0; i < idCount; ++i) { + Debug::log(Debug::Spam) << " id=" << ids[i] << Debug::flush; + NPObject* obj = localObjects.get(ids[i]); + if (!NPN_RemoveProperty(getNPP(), obj, gwtId)) { + Debug::log(Debug::Error) << "Unable to remove GWT ID from object " << ids[i] << Debug::flush; + } else { + localObjects.free(ids[i]); + } + } +} + +void ScriptableInstance::loadJsni(HostChannel& channel, const std::string& js) { + NPString npScript; + dupString(js.c_str(), npScript); + NPVariantWrapper npResult(*this); + Debug::log(Debug::Spam) << "loadJsni - \n" << js << Debug::flush; + if (!NPN_Evaluate(getNPP(), window, &npScript, npResult.addressForReturn())) { + Debug::log(Debug::Error) << "loadJsni failed\n" << js << Debug::flush; + } +} + +Value ScriptableInstance::clientMethod_getProperty(HostChannel& channel, int numArgs, const Value* const args) { + if (numArgs != 2 || !args[0].isInt() || (!args[1].isString() && !args[1].isInt())) { + Debug::log(Debug::Error) << "Incorrect invocation of getProperty: #args=" << numArgs << ":"; + for (int i = 0; i < numArgs; ++i) { + Debug::log(Debug::Error) << " " << i << "=" << args[i].toString(); + } + Debug::log(Debug::Error) << Debug::flush; + return Value(); + } + int id = args[0].getInt(); + NPObject* obj = localObjects.get(id); + NPIdentifier propID; + if (args[1].isString()) { + std::string propName = args[1].getString(); + propID = NPN_GetStringIdentifier(propName.c_str()); + } else { + int propNum = args[1].getInt(); + propID = NPN_GetIntIdentifier(propNum); + } + NPVariantWrapper npResult(*this); + if (!NPN_GetProperty(getNPP(), obj, propID, npResult.addressForReturn())) { + Debug::log(Debug::Warning) << "getProperty(id=" << id << ", prop=" + << NPN_UTF8FromIdentifier(propID) << ") failed" << Debug::flush; + return Value(); + } + return npResult.getAsValue(*this); +} + +Value ScriptableInstance::clientMethod_setProperty(HostChannel& channel, int numArgs, const Value* const args) { + if (numArgs != 2 || !args[0].isInt() || (!args[1].isString() && !args[1].isInt())) { + Debug::log(Debug::Error) << "Incorrect invocation of setProperty: #args=" + << numArgs << ":"; + for (int i = 0; i < numArgs; ++i) { + Debug::log(Debug::Error) << " " << i << "=" << args[i].toString(); + } + Debug::log(Debug::Error) << Debug::flush; + return Value(); + } + int id = args[0].getInt(); + NPObject* obj = localObjects.get(id); + NPIdentifier propID; + if (args[1].isString()) { + std::string propName = args[1].getString(); + propID = NPN_GetStringIdentifier(propName.c_str()); + } else { + int propNum = args[1].getInt(); + propID = NPN_GetIntIdentifier(propNum); + } + NPVariantWrapper npValue(*this); + npValue.operator=(args[2]); + if (!NPN_SetProperty(getNPP(), obj, propID, npValue.address())) { + Debug::log(Debug::Warning) << "setProperty(id=" << id << ", prop=" + << NPN_UTF8FromIdentifier(propID) << ", val=" << args[2].toString() + << ") failed" << Debug::flush; + return Value(); + } + return Value(); +} + +/** + * SessionHandler.invoke - used by LoadModule and reactToMessages* to process server-side + * requests to invoke methods in Javascript or the plugin. + */ +bool ScriptableInstance::invokeSpecial(HostChannel& channel, SpecialMethodId dispatchId, + int numArgs, const Value* const args, Value* returnValue) { + switch (dispatchId) { + case SessionHandler::HasMethod: + case SessionHandler::HasProperty: + break; + case SessionHandler::SetProperty: + *returnValue = clientMethod_setProperty(channel, numArgs, args); + return false; + case SessionHandler::GetProperty: + *returnValue = clientMethod_getProperty(channel, numArgs, args); + return false; + default: + break; + } + Debug::log(Debug::Error) << "Unexpected special method " << dispatchId + << " called on plugin; #args=" << numArgs << ":"; + for (int i = 0; i < numArgs; ++i) { + Debug::log(Debug::Error) << " " << i << "=" << args[i].toString(); + } + Debug::log(Debug::Error) << Debug::flush; + // TODO(jat): should we create a real exception object? + std::string buf("unexpected invokeSpecial("); + buf += static_cast<int>(dispatchId); + buf += ")"; + returnValue->setString(buf); + return true; +} + +bool ScriptableInstance::invoke(HostChannel& channel, const Value& thisRef, + const std::string& methodName, int numArgs, const Value* const args, + Value* returnValue) { + Debug::log(Debug::Debugging) << "invokeJS(" << methodName << ", this=" + << thisRef.toString() << ", numArgs=" << numArgs << ")" << Debug::flush; + NPVariantArray varArgs(*this, numArgs + 2); + varArgs[0] = thisRef; + varArgs[1] = methodName; + for (int i = 0; i < numArgs; ++i) { + varArgs[i + 2] = args[i]; + } + const NPVariant* argArray = varArgs.getArray(); + if (Debug::level(Debug::Spam)) { + for (int i = 0; i < varArgs.getSize(); ++i) { + Debug::log(Debug::Spam) << " arg " << i << " is " + << NPVariantProxy::toString(argArray[i]) << Debug::flush; + } + } + NPVariantWrapper wrappedRetVal(*this); + if (!NPN_Invoke(getNPP(), window, jsInvokeID, argArray, varArgs.getSize(), + wrappedRetVal.addressForReturn())) { + Debug::log(Debug::Error) << "*** invokeJS(" << methodName << ", this=" + << thisRef.toString() << ", numArgs=" << numArgs << ") failed" + << Debug::flush; + // TODO(jat): should we create a real exception object? + returnValue->setString("invoke of " + methodName + " failed"); + return true; + } + Debug::log(Debug::Spam) << " wrapped return is " << wrappedRetVal.toString() << Debug::flush; + NPVariantWrapper exceptFlag(*this); + NPVariantWrapper retval(*this); + NPObject* wrappedArray = wrappedRetVal.getAsObject(); + if (!NPN_GetProperty(getNPP(), wrappedArray, idx0, exceptFlag.addressForReturn())) { + Debug::log(Debug::Error) << " Error getting element 0 of wrapped return value (" + << wrappedRetVal << ") on call to " << methodName << Debug::flush; + } + if (!NPN_GetProperty(getNPP(), wrappedArray, idx1, retval.addressForReturn())) { + Debug::log(Debug::Error) << " Error getting element 1 of wrapped return value (" + << wrappedRetVal << ") on call to " << methodName << Debug::flush; + } + Debug::log(Debug::Debugging) << " return value " << retval.toString() << Debug::flush; + *returnValue = retval.getAsValue(*this); + if (exceptFlag.isInt() && exceptFlag.getAsInt() != 0) { + Debug::log(Debug::Debugging) << " exception: " << retval << Debug::flush; + return true; + } + return false; +} + +bool ScriptableInstance::JavaObject_invoke(int objectId, int dispId, + const NPVariant* args, uint32_t numArgs, NPVariant* result) { + Debug::log(Debug::Debugging) << "JavaObject_invoke(dispId= " << dispId << ", numArgs=" << numArgs << ")" << Debug::flush; + if (Debug::level(Debug::Spam)) { + for (uint32_t i = 0; i < numArgs; ++i) { + Debug::log(Debug::Spam) << " " << i << " = " << args[i] << Debug::flush; + } + } + + bool isRawToString = false; + if (dispId == -1) { + dispId = 0; + isRawToString = true; + } + + Value javaThis; + javaThis.setJavaObject(objectId); + scoped_array<Value> vargs(new Value[numArgs]); + for (unsigned i = 0; i < numArgs; ++i) { + vargs[i] = NPVariantProxy::getAsValue(args[i], *this); + } + if (!InvokeMessage::send(*_channel, javaThis, dispId, numArgs, vargs.get())) { + Debug::log(Debug::Error) << "JavaObject_invoke: failed to send invoke message" << Debug::flush; + // TODO(jat): returning false here spams the browser console + return true; + } + Debug::log(Debug::Debugging) << " return from invoke" << Debug::flush; + scoped_ptr<ReturnMessage> retMsg(_channel->reactToMessagesWhileWaitingForReturn(this)); + if (!retMsg.get()) { + Debug::log(Debug::Error) << "JavaObject_invoke: failed to get return value" << Debug::flush; + return false; + } + if (isRawToString) { + // toString() needs the raw value + NPVariantProxy::assignFrom(*this, *result, retMsg->getReturnValue()); + return !retMsg->isException(); + } + // Wrap the result + return makeResult(retMsg->isException(), retMsg->getReturnValue(), result); +} + +bool ScriptableInstance::JavaObject_getProperty(int objectId, int dispId, + NPVariant* result) { + Debug::log(Debug::Debugging) << "JavaObject_getProperty(objectid=" + << objectId << ", dispId=" << dispId << ")" << Debug::flush; + VOID_TO_NPVARIANT(*result); + Value propertyValue = ServerMethods::getProperty(*_channel, this, objectId, dispId); + if (propertyValue.isJsObject()) { + // TODO(jat): special-case for testing + NPObject* npObj = localObjects.get(propertyValue.getJsObjectId()); + OBJECT_TO_NPVARIANT(npObj, *result); + NPN_RetainObject(npObj); + } else { + NPVariantProxy::assignFrom(*this, *result, propertyValue); + } + Debug::log(Debug::Debugging) << " return val=" << propertyValue + << ", NPVariant=" << *result << Debug::flush; + if (NPVariantProxy::isObject(*result)) { + dumpObjectBytes(NPVariantProxy::getAsObject(*result)); + } + if (NPVariantProxy::isObject(*result)) { + Debug::log(Debug::Debugging) << " final return refcount = " + << NPVariantProxy::getAsObject(*result)->referenceCount << Debug::flush; + } + return true; +} + +bool ScriptableInstance::JavaObject_setProperty(int objectId, int dispId, + const NPVariant* npValue) { + Debug::log(Debug::Debugging) << "JavaObject_setProperty(objectid=" + << objectId << ", dispId=" << dispId << ", value=" << *npValue << ")" << Debug::flush; + if (NPVariantProxy::isObject(*npValue)) { + Debug::log(Debug::Debugging) << " before localObj: refcount = " + << NPVariantProxy::getAsObject(*npValue)->referenceCount << Debug::flush; + } + Value value = NPVariantProxy::getAsValue(*npValue, *this, true); + if (NPVariantProxy::isObject(*npValue)) { + Debug::log(Debug::Debugging) << " after localObj: refcount = " + << NPVariantProxy::getAsObject(*npValue)->referenceCount << Debug::flush; + } + if (NPVariantProxy::isObject(*npValue)) { + dumpObjectBytes(NPVariantProxy::getAsObject(*npValue)); + } + Debug::log(Debug::Debugging) << " as value: " << value << Debug::flush; + // TODO: no way to set an actual exception object! (Could ClassCastException on server.) + return ServerMethods::setProperty(*_channel, this, objectId, dispId, value); +} + +bool ScriptableInstance::JavaObject_getToStringTearOff(NPVariant* result) { + Debug::log(Debug::Debugging) << "JavaObject_getToStringTearOff()" << Debug::flush; + VOID_TO_NPVARIANT(*result); + + Value temp; + NPVariantArray varArgs(*this, 3); + temp.setNull(); varArgs[0] = temp; // proxy: no proxy needed + temp.setInt(0); varArgs[1] = temp; // dispId: always 0 for toString() + temp.setInt(0); varArgs[2] = temp; // argCount: always 0 for toString() + + if (!NPN_Invoke(getNPP(), window, jsTearOffID, varArgs.getArray(), 3, result)) { + Debug::log(Debug::Error) << "*** JavaObject_getToStringTearOff() failed" + << Debug::flush; + return true; + } + return true; +} + +JavaObject* ScriptableInstance::createJavaWrapper(int objectId) { + Debug::log(Debug::Debugging) << "createJavaWrapper(objectId=" << objectId << ")" << Debug::flush; + JavaObject* jObj; + hash_map<int, JavaObject*>::iterator it = javaObjects.find(objectId); + if (it != javaObjects.end()) { + jObj = it->second; + NPN_RetainObject(jObj); + return jObj; + } + jObj = JavaObject::create(this, objectId); + javaObjects[objectId] = jObj; + return jObj; +} + +void ScriptableInstance::destroyJavaWrapper(JavaObject* jObj) { + int objectId = jObj->getObjectId(); + if (!javaObjects.erase(objectId)) { + Debug::log(Debug::Error) << "destroyJavaWrapper(id=" << objectId + << "): trying to free unknown JavaObject" << Debug::flush; + } + Debug::log(Debug::Debugging) << "destroyJavaWrapper(id=" << objectId << ")" << Debug::flush; + javaObjectsToFree.insert(objectId); +} + +void ScriptableInstance::sendFreeValues(HostChannel& channel) { + unsigned n = javaObjectsToFree.size(); + if (n) { + scoped_array<int> ids(new int[n]); + int i = 0; + for (std::set<int>::iterator it = javaObjectsToFree.begin(); + it != javaObjectsToFree.end(); ++it) { + ids[i++] = *it; + } + if (ServerMethods::freeJava(channel, this, n, ids.get())) { + javaObjectsToFree.clear(); + } + } +} +
diff --git a/plugins/npapi/VisualStudio/npapi-plugin.vcproj b/plugins/npapi/VisualStudio/npapi-plugin.vcproj index d338c7f..5826c32 100755 --- a/plugins/npapi/VisualStudio/npapi-plugin.vcproj +++ b/plugins/npapi/VisualStudio/npapi-plugin.vcproj
@@ -63,9 +63,9 @@ Name="VCLinkerTool" AdditionalDependencies="ws2_32.lib" ShowProgress="2" - OutputFile="$(ProjectDir)\..\prebuilt\gwtdmp\WINNT_x86-msvc\npOOPHM.dll" + OutputFile="$(ProjectDir)\..\prebuilt\gwt-dev-plugin\WINNT_x86-msvc\npGwtDevPlugin.dll" LinkIncremental="1" - ModuleDefinitionFile="$(ProjectDir)\..\npOOPHM.def" + ModuleDefinitionFile="$(ProjectDir)\..\npGwtDevPlugin.def" GenerateDebugInformation="true" ProgramDatabaseFile="$(IntDir)\$(TargetName).pdb" SubSystem="2" @@ -144,10 +144,10 @@ Name="VCLinkerTool" AdditionalDependencies="ws2_32.lib" ShowProgress="2" - OutputFile="$(ProjectDir)\..\prebuilt\gwtdmp\WINNT_x86-msvc\npOOPHM.dll" + OutputFile="$(ProjectDir)\..\prebuilt\gwt-dev-plugin\WINNT_x86-msvc\npGwtDevPlugin.dll" LinkIncremental="0" AdditionalLibraryDirectories="" - ModuleDefinitionFile="..\npOOPHM.def" + ModuleDefinitionFile="..\npGwtDevPlugin.def" GenerateDebugInformation="true" ProgramDatabaseFile="$(IntDir)\$(TargetName).pdb" SubSystem="2" @@ -349,7 +349,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > <File - RelativePath="..\npOOPHM.rc" + RelativePath="..\npGwtDevPlugin.rc" > </File> </Filter> @@ -423,7 +423,7 @@ > </File> <File - RelativePath="..\npOOPHM.def" + RelativePath="..\npGwtDevPlugin.def" > </File> <File
diff --git a/plugins/npapi/liboophm.r b/plugins/npapi/liboophm.r deleted file mode 100644 index 251d5f4..0000000 --- a/plugins/npapi/liboophm.r +++ /dev/null
@@ -1,25 +0,0 @@ -/* - * Copyright 2008 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -#include <Carbon/Carbon.r> - -// To compile run: -// Rez liboophm.r -o liboophm.rsrc -useDF -// mv liboophm.rsrc prebuilt/extension/platform/Darwin_x86-gcc3/plugins/oophm.plugin/Contents/Resources/liboophm.rsrc - -resource 'STR#' (126) { - { "GWT Hosted-mode plugin", "GWT Hosted-mode plugin" } -};
diff --git a/plugins/npapi/npOOPHM.def b/plugins/npapi/npGwtDevPlugin.def similarity index 100% rename from plugins/npapi/npOOPHM.def rename to plugins/npapi/npGwtDevPlugin.def
diff --git a/plugins/npapi/npOOPHM.rc b/plugins/npapi/npGwtDevPlugin.rc similarity index 100% rename from plugins/npapi/npOOPHM.rc rename to plugins/npapi/npGwtDevPlugin.rc
diff --git a/plugins/npapi/oophm.xpi b/plugins/npapi/oophm.xpi deleted file mode 100644 index 425cdba..0000000 --- a/plugins/npapi/oophm.xpi +++ /dev/null Binary files differ
diff --git a/plugins/npapi/prebuilt/gwtdmp/background.html b/plugins/npapi/prebuilt/gwt-dev-plugin/background.html similarity index 100% rename from plugins/npapi/prebuilt/gwtdmp/background.html rename to plugins/npapi/prebuilt/gwt-dev-plugin/background.html
diff --git a/plugins/npapi/prebuilt/gwtdmp/gwt128.png b/plugins/npapi/prebuilt/gwt-dev-plugin/gwt128.png similarity index 100% rename from plugins/npapi/prebuilt/gwtdmp/gwt128.png rename to plugins/npapi/prebuilt/gwt-dev-plugin/gwt128.png Binary files differ
diff --git a/plugins/npapi/prebuilt/gwtdmp/gwt16.png b/plugins/npapi/prebuilt/gwt-dev-plugin/gwt16.png similarity index 100% rename from plugins/npapi/prebuilt/gwtdmp/gwt16.png rename to plugins/npapi/prebuilt/gwt-dev-plugin/gwt16.png Binary files differ
diff --git a/plugins/npapi/prebuilt/gwtdmp/gwt32.png b/plugins/npapi/prebuilt/gwt-dev-plugin/gwt32.png similarity index 100% rename from plugins/npapi/prebuilt/gwtdmp/gwt32.png rename to plugins/npapi/prebuilt/gwt-dev-plugin/gwt32.png Binary files differ
diff --git a/plugins/npapi/prebuilt/gwtdmp/gwt48.png b/plugins/npapi/prebuilt/gwt-dev-plugin/gwt48.png similarity index 100% rename from plugins/npapi/prebuilt/gwtdmp/gwt48.png rename to plugins/npapi/prebuilt/gwt-dev-plugin/gwt48.png Binary files differ
diff --git a/plugins/npapi/prebuilt/gwtdmp/gwt64.png b/plugins/npapi/prebuilt/gwt-dev-plugin/gwt64.png similarity index 100% rename from plugins/npapi/prebuilt/gwtdmp/gwt64.png rename to plugins/npapi/prebuilt/gwt-dev-plugin/gwt64.png Binary files differ
diff --git a/plugins/npapi/prebuilt/gwtdmp/manifest.json b/plugins/npapi/prebuilt/gwt-dev-plugin/manifest.json similarity index 70% rename from plugins/npapi/prebuilt/gwtdmp/manifest.json rename to plugins/npapi/prebuilt/gwt-dev-plugin/manifest.json index 4dfc66a..fc73f5f 100644 --- a/plugins/npapi/prebuilt/gwtdmp/manifest.json +++ b/plugins/npapi/prebuilt/gwt-dev-plugin/manifest.json
@@ -1,7 +1,8 @@ { - "name": "GWT Development Mode Plugin", + "name": "GWT Developer Plugin", "version": "0.9.0", "description": "A plugin to enable debugging with GWT's Development Mode", + "update_url": "https://dl-ssl.google.com/gwt/plugins/chrome/updates.xml", "icons": { "16": "gwt16.png", "32": "gwt32.png", @@ -17,6 +18,6 @@ } ], "plugins": [ - { "path": "WINNT_x86-msvc/npOOPHM.dll", "public": true } + { "path": "WINNT_x86-msvc/npGwtDevPlugin.dll", "public": true } ] }
diff --git a/plugins/npapi/prebuilt/gwtdmp/record_tab_id.js b/plugins/npapi/prebuilt/gwt-dev-plugin/record_tab_id.js similarity index 100% rename from plugins/npapi/prebuilt/gwtdmp/record_tab_id.js rename to plugins/npapi/prebuilt/gwt-dev-plugin/record_tab_id.js
diff --git a/plugins/npapi/prebuilt/gwtdmp.crx b/plugins/npapi/prebuilt/gwtdmp.crx deleted file mode 100644 index 1538642..0000000 --- a/plugins/npapi/prebuilt/gwtdmp.crx +++ /dev/null Binary files differ
diff --git a/plugins/npapi/prebuilt/gwtdmp/WINNT_x86-msvc/npOOPHM.dll b/plugins/npapi/prebuilt/gwtdmp/WINNT_x86-msvc/npOOPHM.dll deleted file mode 100644 index a1dcaa9..0000000 --- a/plugins/npapi/prebuilt/gwtdmp/WINNT_x86-msvc/npOOPHM.dll +++ /dev/null Binary files differ