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