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 --------------------
42typedef struct
43{
44    NPObject object;
45    double doubleValue;
46    int intValue;
47    NPVariant stringValue;
48    bool boolValue;
49} MyObject;
50
51
52static 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
62static NPIdentifier myPropertyIdentifiers[NUM_PROPERTY_IDENTIFIERS];
63static 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
83static NPIdentifier myMethodIdentifiers[NUM_METHOD_IDENTIFIERS];
84static 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
96static void initializeIdentifiers()
97{
98    NPN_GetStringIdentifiers (myPropertyIdentifierNames, NUM_PROPERTY_IDENTIFIERS, myPropertyIdentifiers);
99    NPN_GetStringIdentifiers (myMethodIdentifierNames, NUM_METHOD_IDENTIFIERS, myMethodIdentifiers);
100};
101
102bool 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
113bool 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
125void 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
141void 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
152void 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
163void setStringValue (MyObject *obj, const NPVariant *variant)
164{
165    NPN_ReleaseVariantValue (&obj->stringValue);
166    NPN_InitializeVariantWithVariant (&obj->stringValue, variant);
167}
168
169void 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
180void getDoubleValue (MyObject *obj, NPVariant *variant)
181{
182    NPN_InitializeVariantWithDouble (variant, obj->doubleValue);
183}
184
185void getIntValue (MyObject *obj, NPVariant *variant)
186{
187    NPN_InitializeVariantWithInt32 (variant, obj->intValue);
188}
189
190void getStringValue (MyObject *obj, NPVariant *variant)
191{
192    NPN_InitializeVariantWithVariant (variant, &obj->stringValue);
193}
194
195void getBooleanValue (MyObject *obj, NPVariant *variant)
196{
197    NPN_InitializeVariantWithBool (variant, obj->boolValue);
198}
199
200void 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
224void 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
246void 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
289NPObject *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
309void myInvalidate ()
310{
311    // Make sure we've released any remaining references to JavaScript objects.
312}
313
314void myDeallocate (MyObject *obj)
315{
316    free ((void *)obj);
317}
318
319static 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};
330static NPClass *myFunctionPtrs = &_myFunctionPtrs;
331
332// --------------------------------------------------------
333
334using namespace JSC;
335using namespace JSC::Bindings;
336
337class GlobalImp : public ObjectImp {
338public:
339    virtual String className() const { return "global"; }
340};
341
342#define BufferSize 200000
343static char code[BufferSize];
344
345const 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
363int 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("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("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}
420