1 /*
2 * Copyright (C) 2004, 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 "NP_jsobject.h"
31
32 #include "PlatformString.h"
33 #include "StringSourceProvider.h"
34 #ifdef ANDROID_NPN_SETEXCEPTION
35 #include "c_runtime.h"
36 #endif // ANDROID_NPN_SETEXCEPTION
37 #include "c_utility.h"
38 #include "c_instance.h"
39 #include "IdentifierRep.h"
40 #include "npruntime_impl.h"
41 #include "npruntime_priv.h"
42 #include "runtime_root.h"
43 #include <runtime/Error.h>
44 #include <runtime/JSGlobalObject.h>
45 #include <runtime/JSLock.h>
46 #include <runtime/PropertyNameArray.h>
47 #include <parser/SourceCode.h>
48 #include <runtime/Completion.h>
49 #include <runtime/Completion.h>
50
51 using namespace JSC;
52 using namespace JSC::Bindings;
53 using namespace WebCore;
54
getListFromVariantArgs(ExecState * exec,const NPVariant * args,unsigned argCount,RootObject * rootObject,MarkedArgumentBuffer & aList)55 static void getListFromVariantArgs(ExecState* exec, const NPVariant* args, unsigned argCount, RootObject* rootObject, MarkedArgumentBuffer& aList)
56 {
57 for (unsigned i = 0; i < argCount; ++i)
58 aList.append(convertNPVariantToValue(exec, &args[i], rootObject));
59 }
60
jsAllocate(NPP,NPClass *)61 static NPObject* jsAllocate(NPP, NPClass*)
62 {
63 return static_cast<NPObject*>(malloc(sizeof(JavaScriptObject)));
64 }
65
jsDeallocate(NPObject * npObj)66 static void jsDeallocate(NPObject* npObj)
67 {
68 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(npObj);
69
70 if (obj->rootObject && obj->rootObject->isValid())
71 obj->rootObject->gcUnprotect(obj->imp);
72
73 if (obj->rootObject)
74 obj->rootObject->deref();
75
76 free(obj);
77 }
78
79 static NPClass javascriptClass = { 1, jsAllocate, jsDeallocate, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
80 static NPClass noScriptClass = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
81
82 NPClass* NPScriptObjectClass = &javascriptClass;
83 static NPClass* NPNoScriptObjectClass = &noScriptClass;
84
_NPN_CreateScriptObject(NPP npp,JSObject * imp,PassRefPtr<RootObject> rootObject)85 NPObject* _NPN_CreateScriptObject(NPP npp, JSObject* imp, PassRefPtr<RootObject> rootObject)
86 {
87 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(_NPN_CreateObject(npp, NPScriptObjectClass));
88
89 obj->rootObject = rootObject.releaseRef();
90
91 if (obj->rootObject)
92 obj->rootObject->gcProtect(imp);
93 obj->imp = imp;
94
95 return reinterpret_cast<NPObject*>(obj);
96 }
97
_NPN_CreateNoScriptObject(void)98 NPObject* _NPN_CreateNoScriptObject(void)
99 {
100 return _NPN_CreateObject(0, NPNoScriptObjectClass);
101 }
102
_NPN_InvokeDefault(NPP,NPObject * o,const NPVariant * args,uint32_t argCount,NPVariant * result)103 bool _NPN_InvokeDefault(NPP, NPObject* o, const NPVariant* args, uint32_t argCount, NPVariant* result)
104 {
105 if (o->_class == NPScriptObjectClass) {
106 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o);
107
108 VOID_TO_NPVARIANT(*result);
109
110 // Lookup the function object.
111 RootObject* rootObject = obj->rootObject;
112 if (!rootObject || !rootObject->isValid())
113 return false;
114
115 ExecState* exec = rootObject->globalObject()->globalExec();
116 JSLock lock(SilenceAssertionsOnly);
117
118 // Call the function object.
119 JSValue function = obj->imp;
120 CallData callData;
121 CallType callType = function.getCallData(callData);
122 if (callType == CallTypeNone)
123 return false;
124
125 MarkedArgumentBuffer argList;
126 getListFromVariantArgs(exec, args, argCount, rootObject, argList);
127 ProtectedPtr<JSGlobalObject> globalObject = rootObject->globalObject();
128 globalObject->globalData()->timeoutChecker.start();
129 JSValue resultV = call(exec, function, callType, callData, function, argList);
130 globalObject->globalData()->timeoutChecker.stop();
131
132 // Convert and return the result of the function call.
133 convertValueToNPVariant(exec, resultV, result);
134 exec->clearException();
135 return true;
136 }
137
138 if (o->_class->invokeDefault)
139 return o->_class->invokeDefault(o, args, argCount, result);
140 VOID_TO_NPVARIANT(*result);
141 return true;
142 }
143
_NPN_Invoke(NPP npp,NPObject * o,NPIdentifier methodName,const NPVariant * args,uint32_t argCount,NPVariant * result)144 bool _NPN_Invoke(NPP npp, NPObject* o, NPIdentifier methodName, const NPVariant* args, uint32_t argCount, NPVariant* result)
145 {
146 if (o->_class == NPScriptObjectClass) {
147 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o);
148
149 IdentifierRep* i = static_cast<IdentifierRep*>(methodName);
150 if (!i->isString())
151 return false;
152
153 // Special case the "eval" method.
154 if (methodName == _NPN_GetStringIdentifier("eval")) {
155 if (argCount != 1)
156 return false;
157 if (args[0].type != NPVariantType_String)
158 return false;
159 return _NPN_Evaluate(npp, o, const_cast<NPString*>(&args[0].value.stringValue), result);
160 }
161
162 // Look up the function object.
163 RootObject* rootObject = obj->rootObject;
164 if (!rootObject || !rootObject->isValid())
165 return false;
166 ExecState* exec = rootObject->globalObject()->globalExec();
167 JSLock lock(SilenceAssertionsOnly);
168 JSValue function = obj->imp->get(exec, identifierFromNPIdentifier(i->string()));
169 CallData callData;
170 CallType callType = function.getCallData(callData);
171 if (callType == CallTypeNone)
172 return false;
173
174 // Call the function object.
175 MarkedArgumentBuffer argList;
176 getListFromVariantArgs(exec, args, argCount, rootObject, argList);
177 ProtectedPtr<JSGlobalObject> globalObject = rootObject->globalObject();
178 globalObject->globalData()->timeoutChecker.start();
179 JSValue resultV = call(exec, function, callType, callData, obj->imp, argList);
180 globalObject->globalData()->timeoutChecker.stop();
181
182 // Convert and return the result of the function call.
183 convertValueToNPVariant(exec, resultV, result);
184 exec->clearException();
185 return true;
186 }
187
188 if (o->_class->invoke)
189 return o->_class->invoke(o, methodName, args, argCount, result);
190
191 VOID_TO_NPVARIANT(*result);
192 return true;
193 }
194
_NPN_Evaluate(NPP,NPObject * o,NPString * s,NPVariant * variant)195 bool _NPN_Evaluate(NPP, NPObject* o, NPString* s, NPVariant* variant)
196 {
197 if (o->_class == NPScriptObjectClass) {
198 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o);
199
200 RootObject* rootObject = obj->rootObject;
201 if (!rootObject || !rootObject->isValid())
202 return false;
203
204 ExecState* exec = rootObject->globalObject()->globalExec();
205 JSLock lock(SilenceAssertionsOnly);
206 String scriptString = convertNPStringToUTF16(s);
207 ProtectedPtr<JSGlobalObject> globalObject = rootObject->globalObject();
208 globalObject->globalData()->timeoutChecker.start();
209 Completion completion = JSC::evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(scriptString));
210 globalObject->globalData()->timeoutChecker.stop();
211 ComplType type = completion.complType();
212
213 JSValue result;
214 if (type == Normal) {
215 result = completion.value();
216 if (!result)
217 result = jsUndefined();
218 } else
219 result = jsUndefined();
220
221 convertValueToNPVariant(exec, result, variant);
222 exec->clearException();
223 return true;
224 }
225
226 VOID_TO_NPVARIANT(*variant);
227 return false;
228 }
229
_NPN_GetProperty(NPP,NPObject * o,NPIdentifier propertyName,NPVariant * variant)230 bool _NPN_GetProperty(NPP, NPObject* o, NPIdentifier propertyName, NPVariant* variant)
231 {
232 if (o->_class == NPScriptObjectClass) {
233 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o);
234
235 RootObject* rootObject = obj->rootObject;
236 if (!rootObject || !rootObject->isValid())
237 return false;
238
239 ExecState* exec = rootObject->globalObject()->globalExec();
240 IdentifierRep* i = static_cast<IdentifierRep*>(propertyName);
241
242 JSLock lock(SilenceAssertionsOnly);
243 JSValue result;
244 if (i->isString())
245 result = obj->imp->get(exec, identifierFromNPIdentifier(i->string()));
246 else
247 result = obj->imp->get(exec, i->number());
248
249 convertValueToNPVariant(exec, result, variant);
250 exec->clearException();
251 return true;
252 }
253
254 if (o->_class->hasProperty && o->_class->getProperty) {
255 if (o->_class->hasProperty(o, propertyName))
256 return o->_class->getProperty(o, propertyName, variant);
257 return false;
258 }
259
260 VOID_TO_NPVARIANT(*variant);
261 return false;
262 }
263
_NPN_SetProperty(NPP,NPObject * o,NPIdentifier propertyName,const NPVariant * variant)264 bool _NPN_SetProperty(NPP, NPObject* o, NPIdentifier propertyName, const NPVariant* variant)
265 {
266 if (o->_class == NPScriptObjectClass) {
267 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o);
268
269 RootObject* rootObject = obj->rootObject;
270 if (!rootObject || !rootObject->isValid())
271 return false;
272
273 ExecState* exec = rootObject->globalObject()->globalExec();
274 JSLock lock(SilenceAssertionsOnly);
275 IdentifierRep* i = static_cast<IdentifierRep*>(propertyName);
276
277 if (i->isString()) {
278 PutPropertySlot slot;
279 obj->imp->put(exec, identifierFromNPIdentifier(i->string()), convertNPVariantToValue(exec, variant, rootObject), slot);
280 } else
281 obj->imp->put(exec, i->number(), convertNPVariantToValue(exec, variant, rootObject));
282 exec->clearException();
283 return true;
284 }
285
286 if (o->_class->setProperty)
287 return o->_class->setProperty(o, propertyName, variant);
288
289 return false;
290 }
291
_NPN_RemoveProperty(NPP,NPObject * o,NPIdentifier propertyName)292 bool _NPN_RemoveProperty(NPP, NPObject* o, NPIdentifier propertyName)
293 {
294 if (o->_class == NPScriptObjectClass) {
295 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o);
296
297 RootObject* rootObject = obj->rootObject;
298 if (!rootObject || !rootObject->isValid())
299 return false;
300
301 ExecState* exec = rootObject->globalObject()->globalExec();
302 IdentifierRep* i = static_cast<IdentifierRep*>(propertyName);
303 if (i->isString()) {
304 if (!obj->imp->hasProperty(exec, identifierFromNPIdentifier(i->string()))) {
305 exec->clearException();
306 return false;
307 }
308 } else {
309 if (!obj->imp->hasProperty(exec, i->number())) {
310 exec->clearException();
311 return false;
312 }
313 }
314
315 JSLock lock(SilenceAssertionsOnly);
316 if (i->isString())
317 obj->imp->deleteProperty(exec, identifierFromNPIdentifier(i->string()));
318 else
319 obj->imp->deleteProperty(exec, i->number());
320
321 exec->clearException();
322 return true;
323 }
324 return false;
325 }
326
_NPN_HasProperty(NPP,NPObject * o,NPIdentifier propertyName)327 bool _NPN_HasProperty(NPP, NPObject* o, NPIdentifier propertyName)
328 {
329 if (o->_class == NPScriptObjectClass) {
330 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o);
331
332 RootObject* rootObject = obj->rootObject;
333 if (!rootObject || !rootObject->isValid())
334 return false;
335
336 ExecState* exec = rootObject->globalObject()->globalExec();
337 IdentifierRep* i = static_cast<IdentifierRep*>(propertyName);
338 JSLock lock(SilenceAssertionsOnly);
339 if (i->isString()) {
340 bool result = obj->imp->hasProperty(exec, identifierFromNPIdentifier(i->string()));
341 exec->clearException();
342 return result;
343 }
344
345 bool result = obj->imp->hasProperty(exec, i->number());
346 exec->clearException();
347 return result;
348 }
349
350 if (o->_class->hasProperty)
351 return o->_class->hasProperty(o, propertyName);
352
353 return false;
354 }
355
_NPN_HasMethod(NPP,NPObject * o,NPIdentifier methodName)356 bool _NPN_HasMethod(NPP, NPObject* o, NPIdentifier methodName)
357 {
358 if (o->_class == NPScriptObjectClass) {
359 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o);
360
361 IdentifierRep* i = static_cast<IdentifierRep*>(methodName);
362 if (!i->isString())
363 return false;
364
365 RootObject* rootObject = obj->rootObject;
366 if (!rootObject || !rootObject->isValid())
367 return false;
368
369 ExecState* exec = rootObject->globalObject()->globalExec();
370 JSLock lock(SilenceAssertionsOnly);
371 JSValue func = obj->imp->get(exec, identifierFromNPIdentifier(i->string()));
372 exec->clearException();
373 return !func.isUndefined();
374 }
375
376 if (o->_class->hasMethod)
377 return o->_class->hasMethod(o, methodName);
378
379 return false;
380 }
381
382 #ifdef ANDROID_NPN_SETEXCEPTION
_NPN_SetException(NPObject * o,const NPUTF8 * message)383 void _NPN_SetException(NPObject* o, const NPUTF8* message)
384 #else
385 void _NPN_SetException(NPObject*, const NPUTF8* message)
386 #endif
387 {
388 #ifdef ANDROID_NPN_SETEXCEPTION
389 if (o->_class == NPScriptObjectClass) {
390 JSC::Bindings::SetGlobalException(message);
391 }
392 #else
393 // Ignorning the NPObject param is consistent with the Mozilla implementation.
394 UString exception(message);
395 CInstance::setGlobalException(exception);
396 #endif // ANDROID_NPN_SETEXCEPTION
397 }
398
_NPN_Enumerate(NPP,NPObject * o,NPIdentifier ** identifier,uint32_t * count)399 bool _NPN_Enumerate(NPP, NPObject* o, NPIdentifier** identifier, uint32_t* count)
400 {
401 if (o->_class == NPScriptObjectClass) {
402 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o);
403
404 RootObject* rootObject = obj->rootObject;
405 if (!rootObject || !rootObject->isValid())
406 return false;
407
408 ExecState* exec = rootObject->globalObject()->globalExec();
409 JSLock lock(SilenceAssertionsOnly);
410 PropertyNameArray propertyNames(exec);
411
412 obj->imp->getPropertyNames(exec, propertyNames);
413 unsigned size = static_cast<unsigned>(propertyNames.size());
414 // FIXME: This should really call NPN_MemAlloc but that's in WebKit
415 NPIdentifier* identifiers = static_cast<NPIdentifier*>(malloc(sizeof(NPIdentifier) * size));
416
417 for (unsigned i = 0; i < size; ++i)
418 identifiers[i] = _NPN_GetStringIdentifier(propertyNames[i].ustring().UTF8String().c_str());
419
420 *identifier = identifiers;
421 *count = size;
422
423 exec->clearException();
424 return true;
425 }
426
427 if (NP_CLASS_STRUCT_VERSION_HAS_ENUM(o->_class) && o->_class->enumerate)
428 return o->_class->enumerate(o, identifier, count);
429
430 return false;
431 }
432
_NPN_Construct(NPP,NPObject * o,const NPVariant * args,uint32_t argCount,NPVariant * result)433 bool _NPN_Construct(NPP, NPObject* o, const NPVariant* args, uint32_t argCount, NPVariant* result)
434 {
435 if (o->_class == NPScriptObjectClass) {
436 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o);
437
438 VOID_TO_NPVARIANT(*result);
439
440 // Lookup the constructor object.
441 RootObject* rootObject = obj->rootObject;
442 if (!rootObject || !rootObject->isValid())
443 return false;
444
445 ExecState* exec = rootObject->globalObject()->globalExec();
446 JSLock lock(SilenceAssertionsOnly);
447
448 // Call the constructor object.
449 JSValue constructor = obj->imp;
450 ConstructData constructData;
451 ConstructType constructType = constructor.getConstructData(constructData);
452 if (constructType == ConstructTypeNone)
453 return false;
454
455 MarkedArgumentBuffer argList;
456 getListFromVariantArgs(exec, args, argCount, rootObject, argList);
457 ProtectedPtr<JSGlobalObject> globalObject = rootObject->globalObject();
458 globalObject->globalData()->timeoutChecker.start();
459 JSValue resultV = construct(exec, constructor, constructType, constructData, argList);
460 globalObject->globalData()->timeoutChecker.stop();
461
462 // Convert and return the result.
463 convertValueToNPVariant(exec, resultV, result);
464 exec->clearException();
465 return true;
466 }
467
468 if (NP_CLASS_STRUCT_VERSION_HAS_CTOR(o->_class) && o->_class->construct)
469 return o->_class->construct(o, args, argCount, result);
470
471 return false;
472 }
473
474 #endif // ENABLE(NETSCAPE_PLUGIN_API)
475