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 "npruntime_impl.h"
40 #include "npruntime_priv.h"
41 #include "runtime_root.h"
42 #include <runtime/Error.h>
43 #include <runtime/JSGlobalObject.h>
44 #include <runtime/JSLock.h>
45 #include <runtime/PropertyNameArray.h>
46 #include <parser/SourceCode.h>
47 #include <runtime/Completion.h>
48 #include <runtime/Completion.h>
49
50 using WebCore::String;
51 using WebCore::StringSourceProvider;
52 using namespace JSC;
53 using namespace JSC::Bindings;
54
getListFromVariantArgs(ExecState * exec,const NPVariant * args,unsigned argCount,RootObject * rootObject,ArgList & aList)55 static void getListFromVariantArgs(ExecState* exec, const NPVariant* args, unsigned argCount, RootObject* rootObject, ArgList& 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(false);
117
118 // Call the function object.
119 JSValuePtr function = obj->imp;
120 CallData callData;
121 CallType callType = function.getCallData(callData);
122 if (callType == CallTypeNone)
123 return false;
124
125 ArgList argList;
126 getListFromVariantArgs(exec, args, argCount, rootObject, argList);
127 ProtectedPtr<JSGlobalObject> globalObject = rootObject->globalObject();
128 globalObject->startTimeoutCheck();
129 JSValuePtr resultV = call(exec, function, callType, callData, function, argList);
130 globalObject->stopTimeoutCheck();
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 PrivateIdentifier* i = static_cast<PrivateIdentifier*>(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(false);
168 JSValuePtr function = obj->imp->get(exec, identifierFromNPIdentifier(i->value.string));
169 CallData callData;
170 CallType callType = function.getCallData(callData);
171 if (callType == CallTypeNone)
172 return false;
173
174 // Call the function object.
175 ArgList argList;
176 getListFromVariantArgs(exec, args, argCount, rootObject, argList);
177 ProtectedPtr<JSGlobalObject> globalObject = rootObject->globalObject();
178 globalObject->startTimeoutCheck();
179 JSValuePtr resultV = call(exec, function, callType, callData, obj->imp, argList);
180 globalObject->stopTimeoutCheck();
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(false);
206 String scriptString = convertNPStringToUTF16(s);
207 ProtectedPtr<JSGlobalObject> globalObject = rootObject->globalObject();
208 globalObject->startTimeoutCheck();
209 Completion completion = JSC::evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(scriptString));
210 globalObject->stopTimeoutCheck();
211 ComplType type = completion.complType();
212
213 JSValuePtr 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 PrivateIdentifier* i = static_cast<PrivateIdentifier*>(propertyName);
241
242 JSLock lock(false);
243 JSValuePtr result;
244 if (i->isString)
245 result = obj->imp->get(exec, identifierFromNPIdentifier(i->value.string));
246 else
247 result = obj->imp->get(exec, i->value.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(false);
275 PrivateIdentifier* i = static_cast<PrivateIdentifier*>(propertyName);
276
277 if (i->isString) {
278 PutPropertySlot slot;
279 obj->imp->put(exec, identifierFromNPIdentifier(i->value.string), convertNPVariantToValue(exec, variant, rootObject), slot);
280 } else
281 obj->imp->put(exec, i->value.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 PrivateIdentifier* i = static_cast<PrivateIdentifier*>(propertyName);
303 if (i->isString) {
304 if (!obj->imp->hasProperty(exec, identifierFromNPIdentifier(i->value.string))) {
305 exec->clearException();
306 return false;
307 }
308 } else {
309 if (!obj->imp->hasProperty(exec, i->value.number)) {
310 exec->clearException();
311 return false;
312 }
313 }
314
315 JSLock lock(false);
316 if (i->isString)
317 obj->imp->deleteProperty(exec, identifierFromNPIdentifier(i->value.string));
318 else
319 obj->imp->deleteProperty(exec, i->value.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 PrivateIdentifier* i = static_cast<PrivateIdentifier*>(propertyName);
338 JSLock lock(false);
339 if (i->isString) {
340 bool result = obj->imp->hasProperty(exec, identifierFromNPIdentifier(i->value.string));
341 exec->clearException();
342 return result;
343 }
344
345 bool result = obj->imp->hasProperty(exec, i->value.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 PrivateIdentifier* i = static_cast<PrivateIdentifier*>(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(false);
371 JSValuePtr func = obj->imp->get(exec, identifierFromNPIdentifier(i->value.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
_NPN_SetException(NPObject * o,const NPUTF8 * message)382 void _NPN_SetException(NPObject* o, const NPUTF8* message)
383 {
384 #ifdef ANDROID_NPN_SETEXCEPTION
385 if (o->_class == NPScriptObjectClass) {
386 JSC::Bindings::SetGlobalException(message);
387 }
388 #else
389 // Ignorning the NPObject param is consistent with the Mozilla implementation.
390 UString exception(message);
391 CInstance::setGlobalException(exception);
392 #endif // ANDROID_NPN_SETEXCEPTION
393 }
394
_NPN_Enumerate(NPP,NPObject * o,NPIdentifier ** identifier,uint32_t * count)395 bool _NPN_Enumerate(NPP, NPObject* o, NPIdentifier** identifier, uint32_t* count)
396 {
397 if (o->_class == NPScriptObjectClass) {
398 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o);
399
400 RootObject* rootObject = obj->rootObject;
401 if (!rootObject || !rootObject->isValid())
402 return false;
403
404 ExecState* exec = rootObject->globalObject()->globalExec();
405 JSLock lock(false);
406 PropertyNameArray propertyNames(exec);
407
408 obj->imp->getPropertyNames(exec, propertyNames);
409 unsigned size = static_cast<unsigned>(propertyNames.size());
410 // FIXME: This should really call NPN_MemAlloc but that's in WebKit
411 NPIdentifier* identifiers = static_cast<NPIdentifier*>(malloc(sizeof(NPIdentifier) * size));
412
413 for (unsigned i = 0; i < size; ++i)
414 identifiers[i] = _NPN_GetStringIdentifier(propertyNames[i].ustring().UTF8String().c_str());
415
416 *identifier = identifiers;
417 *count = size;
418
419 exec->clearException();
420 return true;
421 }
422
423 if (NP_CLASS_STRUCT_VERSION_HAS_ENUM(o->_class) && o->_class->enumerate)
424 return o->_class->enumerate(o, identifier, count);
425
426 return false;
427 }
428
_NPN_Construct(NPP,NPObject * o,const NPVariant * args,uint32_t argCount,NPVariant * result)429 bool _NPN_Construct(NPP, NPObject* o, const NPVariant* args, uint32_t argCount, NPVariant* result)
430 {
431 if (o->_class == NPScriptObjectClass) {
432 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o);
433
434 VOID_TO_NPVARIANT(*result);
435
436 // Lookup the constructor object.
437 RootObject* rootObject = obj->rootObject;
438 if (!rootObject || !rootObject->isValid())
439 return false;
440
441 ExecState* exec = rootObject->globalObject()->globalExec();
442 JSLock lock(false);
443
444 // Call the constructor object.
445 JSValuePtr constructor = obj->imp;
446 ConstructData constructData;
447 ConstructType constructType = constructor.getConstructData(constructData);
448 if (constructType == ConstructTypeNone)
449 return false;
450
451 ArgList argList;
452 getListFromVariantArgs(exec, args, argCount, rootObject, argList);
453 ProtectedPtr<JSGlobalObject> globalObject = rootObject->globalObject();
454 globalObject->startTimeoutCheck();
455 JSValuePtr resultV = construct(exec, constructor, constructType, constructData, argList);
456 globalObject->stopTimeoutCheck();
457
458 // Convert and return the result.
459 convertValueToNPVariant(exec, resultV, result);
460 exec->clearException();
461 return true;
462 }
463
464 if (NP_CLASS_STRUCT_VERSION_HAS_CTOR(o->_class) && o->_class->construct)
465 return o->_class->construct(o, args, argCount, result);
466
467 return false;
468 }
469
470 #endif // ENABLE(NETSCAPE_PLUGIN_API)
471