1 /* 2 * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 28 #if ENABLE(NETSCAPE_PLUGIN_API) 29 30 #include "c_instance.h" 31 32 #include "c_class.h" 33 #include "c_runtime.h" 34 #include "c_utility.h" 35 #include "IdentifierRep.h" 36 #include "npruntime_impl.h" 37 #include "runtime_root.h" 38 #include <runtime/ArgList.h> 39 #include <runtime/Error.h> 40 #include <interpreter/CallFrame.h> 41 #include <runtime/JSLock.h> 42 #include <runtime/JSNumberCell.h> 43 #include <runtime/PropertyNameArray.h> 44 #include <wtf/Assertions.h> 45 #include <wtf/StdLibExtras.h> 46 #include <wtf/StringExtras.h> 47 #include <wtf/Vector.h> 48 49 using namespace WebCore; 50 51 namespace JSC { 52 namespace Bindings { 53 54 using JSC::UString; 55 56 static JSC::UString& globalExceptionString() 57 { 58 DEFINE_STATIC_LOCAL(JSC::UString, exceptionStr, ()); 59 return exceptionStr; 60 } 61 62 void CInstance::setGlobalException(UString exception) 63 { 64 globalExceptionString() = exception; 65 } 66 67 void CInstance::moveGlobalExceptionToExecState(ExecState* exec) 68 { 69 if (globalExceptionString().isNull()) 70 return; 71 72 { 73 JSLock lock(SilenceAssertionsOnly); 74 throwError(exec, GeneralError, globalExceptionString()); 75 } 76 77 globalExceptionString() = UString(); 78 } 79 80 CInstance::CInstance(NPObject* o, PassRefPtr<RootObject> rootObject) 81 : Instance(rootObject) 82 { 83 _object = _NPN_RetainObject(o); 84 _class = 0; 85 } 86 87 CInstance::~CInstance() 88 { 89 _NPN_ReleaseObject(_object); 90 } 91 92 Class *CInstance::getClass() const 93 { 94 if (!_class) 95 _class = CClass::classForIsA(_object->_class); 96 return _class; 97 } 98 99 bool CInstance::supportsInvokeDefaultMethod() const 100 { 101 return _object->_class->invokeDefault; 102 } 103 104 JSValue CInstance::invokeMethod(ExecState* exec, const MethodList& methodList, const ArgList& args) 105 { 106 // Overloading methods are not allowed by NPObjects. Should only be one 107 // name match for a particular method. 108 ASSERT(methodList.size() == 1); 109 110 CMethod* method = static_cast<CMethod*>(methodList[0]); 111 112 NPIdentifier ident = method->identifier(); 113 if (!_object->_class->hasMethod(_object, ident)) 114 return jsUndefined(); 115 116 unsigned count = args.size(); 117 Vector<NPVariant, 8> cArgs(count); 118 119 unsigned i; 120 for (i = 0; i < count; i++) 121 convertValueToNPVariant(exec, args.at(i), &cArgs[i]); 122 123 // Invoke the 'C' method. 124 bool retval = true; 125 NPVariant resultVariant; 126 VOID_TO_NPVARIANT(resultVariant); 127 128 { 129 JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly); 130 ASSERT(globalExceptionString().isNull()); 131 retval = _object->_class->invoke(_object, ident, cArgs.data(), count, &resultVariant); 132 moveGlobalExceptionToExecState(exec); 133 } 134 135 if (!retval) 136 throwError(exec, GeneralError, "Error calling method on NPObject!"); 137 138 for (i = 0; i < count; i++) 139 _NPN_ReleaseVariantValue(&cArgs[i]); 140 141 JSValue resultValue = convertNPVariantToValue(exec, &resultVariant, m_rootObject.get()); 142 _NPN_ReleaseVariantValue(&resultVariant); 143 return resultValue; 144 } 145 146 147 JSValue CInstance::invokeDefaultMethod(ExecState* exec, const ArgList& args) 148 { 149 if (!_object->_class->invokeDefault) 150 return jsUndefined(); 151 152 unsigned count = args.size(); 153 Vector<NPVariant, 8> cArgs(count); 154 155 unsigned i; 156 for (i = 0; i < count; i++) 157 convertValueToNPVariant(exec, args.at(i), &cArgs[i]); 158 159 // Invoke the 'C' method. 160 bool retval = true; 161 NPVariant resultVariant; 162 VOID_TO_NPVARIANT(resultVariant); 163 { 164 JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly); 165 ASSERT(globalExceptionString().isNull()); 166 retval = _object->_class->invokeDefault(_object, cArgs.data(), count, &resultVariant); 167 moveGlobalExceptionToExecState(exec); 168 } 169 170 if (!retval) 171 throwError(exec, GeneralError, "Error calling method on NPObject!"); 172 173 for (i = 0; i < count; i++) 174 _NPN_ReleaseVariantValue(&cArgs[i]); 175 176 JSValue resultValue = convertNPVariantToValue(exec, &resultVariant, m_rootObject.get()); 177 _NPN_ReleaseVariantValue(&resultVariant); 178 return resultValue; 179 } 180 181 bool CInstance::supportsConstruct() const 182 { 183 return _object->_class->construct; 184 } 185 186 JSValue CInstance::invokeConstruct(ExecState* exec, const ArgList& args) 187 { 188 if (!_object->_class->construct) 189 return jsUndefined(); 190 191 unsigned count = args.size(); 192 Vector<NPVariant, 8> cArgs(count); 193 194 unsigned i; 195 for (i = 0; i < count; i++) 196 convertValueToNPVariant(exec, args.at(i), &cArgs[i]); 197 198 // Invoke the 'C' method. 199 bool retval = true; 200 NPVariant resultVariant; 201 VOID_TO_NPVARIANT(resultVariant); 202 { 203 JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly); 204 ASSERT(globalExceptionString().isNull()); 205 retval = _object->_class->construct(_object, cArgs.data(), count, &resultVariant); 206 moveGlobalExceptionToExecState(exec); 207 } 208 209 if (!retval) 210 throwError(exec, GeneralError, "Error calling method on NPObject!"); 211 212 for (i = 0; i < count; i++) 213 _NPN_ReleaseVariantValue(&cArgs[i]); 214 215 JSValue resultValue = convertNPVariantToValue(exec, &resultVariant, m_rootObject.get()); 216 _NPN_ReleaseVariantValue(&resultVariant); 217 return resultValue; 218 } 219 220 JSValue CInstance::defaultValue(ExecState* exec, PreferredPrimitiveType hint) const 221 { 222 if (hint == PreferString) 223 return stringValue(exec); 224 if (hint == PreferNumber) 225 return numberValue(exec); 226 return valueOf(exec); 227 } 228 229 JSValue CInstance::stringValue(ExecState* exec) const 230 { 231 char buf[1024]; 232 snprintf(buf, sizeof(buf), "NPObject %p, NPClass %p", _object, _object->_class); 233 return jsString(exec, buf); 234 } 235 236 JSValue CInstance::numberValue(ExecState* exec) const 237 { 238 // FIXME: Implement something sensible. 239 return jsNumber(exec, 0); 240 } 241 242 JSValue CInstance::booleanValue() const 243 { 244 // FIXME: Implement something sensible. 245 return jsBoolean(false); 246 } 247 248 JSValue CInstance::valueOf(ExecState* exec) const 249 { 250 return stringValue(exec); 251 } 252 253 void CInstance::getPropertyNames(ExecState* exec, PropertyNameArray& nameArray) 254 { 255 if (!NP_CLASS_STRUCT_VERSION_HAS_ENUM(_object->_class) || !_object->_class->enumerate) 256 return; 257 258 uint32_t count; 259 NPIdentifier* identifiers; 260 261 { 262 JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly); 263 ASSERT(globalExceptionString().isNull()); 264 bool ok = _object->_class->enumerate(_object, &identifiers, &count); 265 moveGlobalExceptionToExecState(exec); 266 if (!ok) 267 return; 268 } 269 270 for (uint32_t i = 0; i < count; i++) { 271 IdentifierRep* identifier = static_cast<IdentifierRep*>(identifiers[i]); 272 273 if (identifier->isString()) 274 nameArray.add(identifierFromNPIdentifier(identifier->string())); 275 else 276 nameArray.add(Identifier::from(exec, identifier->number())); 277 } 278 279 // FIXME: This should really call NPN_MemFree but that's in WebKit 280 free(identifiers); 281 } 282 283 } 284 } 285 286 #endif // ENABLE(NETSCAPE_PLUGIN_API) 287