Home | History | Annotate | Download | only in bridge
      1 /*
      2  *  Copyright (C) 1999-2000 Harri Porten (porten (at) 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 "JSObject.h"
     25 #include "JSValue.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 UString 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("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).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