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