[JSC] Weak should only accept cell pointees.
[WebKit-https.git] / Source / WebCore / bridge / testbindings.cpp
1 /*
2  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Library General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Library General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Library General Public License
16  *  along with this library; see the file COPYING.LIB.  If not, write to
17  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  *  Boston, MA 02110-1301, USA.
19  *
20  */
21 #include "config.h"
22
23 #include "BridgeJSC.h"
24 #include "JSCJSValue.h"
25 #include "JSObject.h"
26 #include "interpreter.h"
27 #include "npruntime_internal.h"
28 #include "runtime_object.h"
29 #include "types.h"
30 #include <assert.h>
31 #include <stdio.h>
32 #include <string.h>
33
34
35 #define LOG(formatAndArgs...) { \
36     fprintf (stderr, "%s:  ", __PRETTY_FUNCTION__); \
37     fprintf(stderr, formatAndArgs); \
38 }
39
40
41 // ------------------ NP Interface definition --------------------
42 typedef struct
43 {
44     NPObject object;
45     double doubleValue;
46     int intValue;
47     NPVariant stringValue;
48     bool boolValue;
49 } MyObject;
50
51
52 static bool identifiersInitialized = false;
53
54 #define ID_DOUBLE_VALUE                         0
55 #define ID_INT_VALUE                            1
56 #define ID_STRING_VALUE                         2
57 #define ID_BOOLEAN_VALUE                        3
58 #define ID_NULL_VALUE                           4
59 #define ID_UNDEFINED_VALUE                      5
60 #define NUM_PROPERTY_IDENTIFIERS                6
61
62 static NPIdentifier myPropertyIdentifiers[NUM_PROPERTY_IDENTIFIERS];
63 static const NPUTF8 *myPropertyIdentifierNames[NUM_PROPERTY_IDENTIFIERS] = {
64     "doubleValue",
65     "intValue",
66     "stringValue",
67     "booleanValue",
68     "nullValue",
69     "undefinedValue"
70 };
71
72 #define ID_LOG_MESSAGE                          0
73 #define ID_SET_DOUBLE_VALUE                     1
74 #define ID_SET_INT_VALUE                        2
75 #define ID_SET_STRING_VALUE                     3
76 #define ID_SET_BOOLEAN_VALUE                    4
77 #define ID_GET_DOUBLE_VALUE                     5
78 #define ID_GET_INT_VALUE                        6
79 #define ID_GET_STRING_VALUE                     7
80 #define ID_GET_BOOLEAN_VALUE                    8
81 #define NUM_METHOD_IDENTIFIERS                  9
82
83 static NPIdentifier myMethodIdentifiers[NUM_METHOD_IDENTIFIERS];
84 static const NPUTF8 *myMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = {
85     "logMessage",
86     "setDoubleValue",
87     "setIntValue",
88     "setStringValue",
89     "setBooleanValue",
90     "getDoubleValue",
91     "getIntValue",
92     "getStringValue",
93     "getBooleanValue"
94 };
95
96 static void initializeIdentifiers()
97 {
98     NPN_GetStringIdentifiers (myPropertyIdentifierNames, NUM_PROPERTY_IDENTIFIERS, myPropertyIdentifiers);
99     NPN_GetStringIdentifiers (myMethodIdentifierNames, NUM_METHOD_IDENTIFIERS, myMethodIdentifiers);
100 };
101
102 bool myHasProperty (NPClass *theClass, NPIdentifier name)
103 {
104     int i;
105     for (i = 0; i < NUM_PROPERTY_IDENTIFIERS; i++) {
106         if (name == myPropertyIdentifiers[i]){
107             return true;
108         }
109     }
110     return false;
111 }
112
113 bool myHasMethod (NPClass *theClass, NPIdentifier name)
114 {
115     int i;
116     for (i = 0; i < NUM_METHOD_IDENTIFIERS; i++) {
117         if (name == myMethodIdentifiers[i]){
118             return true;
119         }
120     }
121     return false;
122 }
123
124
125 void logMessage (const NPVariant *message)
126 {
127     if (message->type == NPVariantStringType) {
128         char msgBuf[1024];
129         strncpy (msgBuf, message->value.stringValue.UTF8Characters, message->value.stringValue.UTF8Length);
130         msgBuf[message->value.stringValue.UTF8Length] = 0;
131         printf ("%s\n", msgBuf);
132     }
133     else if (message->type == NPVariantDoubleType)
134         printf ("%f\n", (float)message->value.doubleValue);
135     else if (message->type == NPVariantInt32Type)
136         printf ("%d\n", message->value.intValue);
137     else if (message->type == NPVariantObjectType)
138         printf ("%p\n", message->value.objectValue);
139 }
140
141 void setDoubleValue (MyObject *obj, const NPVariant *variant)
142 {
143     if (!NPN_VariantToDouble (variant, &obj->doubleValue)) {
144         NPUTF8 *msg = "Attempt to set double value with invalid type.";
145         NPString aString;
146         aString.UTF8Characters = msg;
147         aString.UTF8Length = strlen (msg);
148         NPN_SetException ((NPObject *)obj, &aString);
149     }
150 }
151
152 void setIntValue (MyObject *obj, const NPVariant *variant)
153 {
154     if (!NPN_VariantToInt32 (variant, &obj->intValue)) {
155         NPUTF8 *msg = "Attempt to set int value with invalid type.";
156         NPString aString;
157         aString.UTF8Characters = msg;
158         aString.UTF8Length = strlen (msg);
159         NPN_SetException ((NPObject *)obj, &aString);
160     }
161 }
162
163 void setStringValue (MyObject *obj, const NPVariant *variant)
164 {
165     NPN_ReleaseVariantValue (&obj->stringValue);
166     NPN_InitializeVariantWithVariant (&obj->stringValue, variant);
167 }
168
169 void setBooleanValue (MyObject *obj, const NPVariant *variant)
170 {
171     if (!NPN_VariantToBool (variant, (NPBool *)&obj->boolValue)) {
172         NPUTF8 *msg = "Attempt to set bool value with invalid type.";
173         NPString aString;
174         aString.UTF8Characters = msg;
175         aString.UTF8Length = strlen (msg);
176         NPN_SetException ((NPObject *)obj, &aString);
177     }
178 }
179
180 void getDoubleValue (MyObject *obj, NPVariant *variant)
181 {
182     NPN_InitializeVariantWithDouble (variant, obj->doubleValue);
183 }
184
185 void getIntValue (MyObject *obj, NPVariant *variant)
186 {
187     NPN_InitializeVariantWithInt32 (variant, obj->intValue);
188 }
189
190 void getStringValue (MyObject *obj, NPVariant *variant)
191 {
192     NPN_InitializeVariantWithVariant (variant, &obj->stringValue);
193 }
194
195 void getBooleanValue (MyObject *obj, NPVariant *variant)
196 {
197     NPN_InitializeVariantWithBool (variant, obj->boolValue);
198 }
199
200 void myGetProperty (MyObject *obj, NPIdentifier name, NPVariant *variant)
201 {
202     if (name == myPropertyIdentifiers[ID_DOUBLE_VALUE]){
203         getDoubleValue (obj, variant);
204     }
205     else if (name == myPropertyIdentifiers[ID_INT_VALUE]){
206         getIntValue (obj, variant);
207     }
208     else if (name == myPropertyIdentifiers[ID_STRING_VALUE]){
209         getStringValue (obj, variant);
210     }
211     else if (name == myPropertyIdentifiers[ID_BOOLEAN_VALUE]){
212         getBooleanValue (obj, variant);
213     }
214     else if (name == myPropertyIdentifiers[ID_NULL_VALUE]){
215         return NPN_InitializeVariantAsNull (variant);
216     }
217     else if (name == myPropertyIdentifiers[ID_UNDEFINED_VALUE]){
218         return NPN_InitializeVariantAsUndefined (variant); 
219     }
220     else
221         NPN_InitializeVariantAsUndefined(variant);
222 }
223
224 void mySetProperty (MyObject *obj, NPIdentifier name, const NPVariant *variant)
225 {
226     if (name == myPropertyIdentifiers[ID_DOUBLE_VALUE]) {
227         setDoubleValue (obj, variant);
228     }
229     else if (name == myPropertyIdentifiers[ID_INT_VALUE]) {
230         setIntValue (obj, variant);
231     }
232     else if (name == myPropertyIdentifiers[ID_STRING_VALUE]) {
233         setStringValue (obj, variant);
234     }
235     else if (name == myPropertyIdentifiers[ID_BOOLEAN_VALUE]) {
236         setBooleanValue (obj, variant);
237     }
238     else if (name == myPropertyIdentifiers[ID_NULL_VALUE]) {
239         // Do nothing!
240     }
241     else if (name == myPropertyIdentifiers[ID_UNDEFINED_VALUE]) {
242         // Do nothing!
243     }
244 }
245
246 void myInvoke (MyObject *obj, NPIdentifier name, NPVariant *args, unsigned argCount, NPVariant *result)
247 {
248     if (name == myMethodIdentifiers[ID_LOG_MESSAGE]) {
249         if (argCount == 1 && NPN_VariantIsString(&args[0]))
250             logMessage (&args[0]);
251         NPN_InitializeVariantAsVoid (result);
252     }
253     else if (name == myMethodIdentifiers[ID_SET_DOUBLE_VALUE]) {
254         if (argCount == 1 && NPN_VariantIsDouble (&args[0]))
255             setDoubleValue (obj, &args[0]);
256         NPN_InitializeVariantAsVoid (result);
257     }
258     else if (name == myMethodIdentifiers[ID_SET_INT_VALUE]) {
259         if (argCount == 1 && (NPN_VariantIsDouble (&args[0]) || NPN_VariantIsInt32 (&args[0])))
260             setIntValue (obj, &args[0]);
261         NPN_InitializeVariantAsVoid (result);
262     }
263     else if (name == myMethodIdentifiers[ID_SET_STRING_VALUE]) {
264         if (argCount == 1 && NPN_VariantIsString (&args[0]))
265             setStringValue (obj, &args[0]);
266         NPN_InitializeVariantAsVoid (result);
267     }
268     else if (name == myMethodIdentifiers[ID_SET_BOOLEAN_VALUE]) {
269         if (argCount == 1 && NPN_VariantIsBool (&args[0]))
270             setBooleanValue (obj, &args[0]);
271         NPN_InitializeVariantAsVoid (result);
272     }
273     else if (name == myMethodIdentifiers[ID_GET_DOUBLE_VALUE]) {
274         getDoubleValue (obj, result);
275     }
276     else if (name == myMethodIdentifiers[ID_GET_INT_VALUE]) {
277         getIntValue (obj, result);
278     }
279     else if (name == myMethodIdentifiers[ID_GET_STRING_VALUE]) {
280         getStringValue (obj, result);
281     }
282     else if (name == myMethodIdentifiers[ID_GET_BOOLEAN_VALUE]) {
283         getBooleanValue (obj, result);
284     }
285     else 
286         NPN_InitializeVariantAsUndefined (result);
287 }
288
289 NPObject *myAllocate ()
290 {
291     MyObject *newInstance = (MyObject *)malloc (sizeof(MyObject));
292     
293     if (!identifiersInitialized) {
294         identifiersInitialized = true;
295         initializeIdentifiers();
296     }
297     
298     
299     newInstance->doubleValue = 666.666;
300     newInstance->intValue = 1234;
301     newInstance->boolValue = true;
302     newInstance->stringValue.type = NPVariantType_String;
303     newInstance->stringValue.value.stringValue.UTF8Length = strlen ("Hello world");
304     newInstance->stringValue.value.stringValue.UTF8Characters = strdup ("Hello world");
305     
306     return (NPObject *)newInstance;
307 }
308
309 void myInvalidate ()
310 {
311     // Make sure we've released any remaining references to JavaScript objects.
312 }
313
314 void myDeallocate (MyObject *obj) 
315 {
316     free ((void *)obj);
317 }
318
319 static NPClass _myFunctionPtrs = { 
320     kNPClassStructVersionCurrent,
321     (NPAllocateFunctionPtr) myAllocate, 
322     (NPDeallocateFunctionPtr) myDeallocate, 
323     (NPInvalidateFunctionPtr) myInvalidate,
324     (NPHasMethodFunctionPtr) myHasMethod,
325     (NPInvokeFunctionPtr) myInvoke,
326     (NPHasPropertyFunctionPtr) myHasProperty,
327     (NPGetPropertyFunctionPtr) myGetProperty,
328     (NPSetPropertyFunctionPtr) mySetProperty,
329 };
330 static NPClass *myFunctionPtrs = &_myFunctionPtrs;
331
332 // --------------------------------------------------------
333
334 using namespace JSC;
335 using namespace JSC::Bindings;
336
337 class GlobalImp : public ObjectImp {
338 public:
339     virtual String className() const { return "global"; }
340 };
341
342 #define BufferSize 200000
343 static char code[BufferSize];
344
345 const char *readJavaScriptFromFile (const char *file)
346 {
347     FILE *f = fopen(file, "r");
348     if (!f) {
349         fprintf(stderr, "Error opening %s.\n", file);
350         return 0;
351     }
352     
353     int num = fread(code, 1, BufferSize, f);
354     code[num] = '\0';
355     if(num >= BufferSize)
356         fprintf(stderr, "Warning: File may have been too long.\n");
357
358     fclose(f);
359     
360     return code;
361 }
362
363 int main(int argc, char **argv)
364 {
365     // expecting a filename
366     if (argc < 2) {
367         fprintf(stderr, "You have to specify at least one filename\n");
368         return -1;
369     }
370     
371     bool ret = true;
372     {
373         JSLock lock;
374         
375         // create interpreter w/ global object
376         Object global(new GlobalImp());
377         Interpreter interp;
378         interp.setGlobalObject(global);
379         ExecState *exec = interp.globalExec();
380         
381         MyObject *myObject = (MyObject *)NPN_CreateObject (myFunctionPtrs);
382         
383         global.put(exec, Identifier::fromString(exec, "myInterface"), Instance::createRuntimeObject(Instance::CLanguage, (void *)myObject));
384         
385         for (int i = 1; i < argc; i++) {
386             const char *code = readJavaScriptFromFile(argv[i]);
387             
388             if (code) {
389                 // run
390                 Completion comp(interp.evaluate(code));
391                 
392                 if (comp.complType() == Throw) {
393                     Value exVal = comp.value();
394                     char* msg = exVal.toString(exec)->value(exec).ascii();
395                     int lineno = -1;
396                     if (exVal.type() == ObjectType) {
397                         Value lineVal = Object::dynamicCast(exVal).get(exec, Identifier::fromString(exec, "line"));
398                         if (lineVal.type() == NumberType)
399                             lineno = int(lineVal.toNumber(exec));
400                     }
401                     if (lineno != -1)
402                         fprintf(stderr,"Exception, line %d: %s\n",lineno,msg);
403                     else
404                         fprintf(stderr,"Exception: %s\n",msg);
405                     ret = false;
406                 }
407                 else if (comp.complType() == ReturnValue) {
408                     char *msg = comp.value().toString(interp.globalExec()).ascii();
409                     fprintf(stderr,"Return value: %s\n",msg);
410                 }
411             }
412         }
413                 
414         NPN_ReleaseObject ((NPObject *)myObject);
415         
416     } // end block, so that Interpreter and global get deleted
417     
418     return ret ? 0 : 3;
419 }