| /* |
| * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) |
| * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public License |
| * along with this library; see the file COPYING.LIB. If not, write to |
| * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| * |
| */ |
| #include "config.h" |
| |
| #include "BridgeJSC.h" |
| #include "JSCJSValue.h" |
| #include "JSObject.h" |
| #include "interpreter.h" |
| #include "npruntime_internal.h" |
| #include "runtime_object.h" |
| #include "types.h" |
| #include <assert.h> |
| #include <stdio.h> |
| #include <string.h> |
| |
| |
| #define LOG(formatAndArgs...) { \ |
| fprintf (stderr, "%s: ", __PRETTY_FUNCTION__); \ |
| fprintf(stderr, formatAndArgs); \ |
| } |
| |
| |
| // ------------------ NP Interface definition -------------------- |
| typedef struct |
| { |
| NPObject object; |
| double doubleValue; |
| int intValue; |
| NPVariant stringValue; |
| bool boolValue; |
| } MyObject; |
| |
| |
| static bool identifiersInitialized = false; |
| |
| #define ID_DOUBLE_VALUE 0 |
| #define ID_INT_VALUE 1 |
| #define ID_STRING_VALUE 2 |
| #define ID_BOOLEAN_VALUE 3 |
| #define ID_NULL_VALUE 4 |
| #define ID_UNDEFINED_VALUE 5 |
| #define NUM_PROPERTY_IDENTIFIERS 6 |
| |
| static NPIdentifier myPropertyIdentifiers[NUM_PROPERTY_IDENTIFIERS]; |
| static const NPUTF8 *myPropertyIdentifierNames[NUM_PROPERTY_IDENTIFIERS] = { |
| "doubleValue", |
| "intValue", |
| "stringValue", |
| "booleanValue", |
| "nullValue", |
| "undefinedValue" |
| }; |
| |
| #define ID_LOG_MESSAGE 0 |
| #define ID_SET_DOUBLE_VALUE 1 |
| #define ID_SET_INT_VALUE 2 |
| #define ID_SET_STRING_VALUE 3 |
| #define ID_SET_BOOLEAN_VALUE 4 |
| #define ID_GET_DOUBLE_VALUE 5 |
| #define ID_GET_INT_VALUE 6 |
| #define ID_GET_STRING_VALUE 7 |
| #define ID_GET_BOOLEAN_VALUE 8 |
| #define NUM_METHOD_IDENTIFIERS 9 |
| |
| static NPIdentifier myMethodIdentifiers[NUM_METHOD_IDENTIFIERS]; |
| static const NPUTF8 *myMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = { |
| "logMessage", |
| "setDoubleValue", |
| "setIntValue", |
| "setStringValue", |
| "setBooleanValue", |
| "getDoubleValue", |
| "getIntValue", |
| "getStringValue", |
| "getBooleanValue" |
| }; |
| |
| static void initializeIdentifiers() |
| { |
| NPN_GetStringIdentifiers (myPropertyIdentifierNames, NUM_PROPERTY_IDENTIFIERS, myPropertyIdentifiers); |
| NPN_GetStringIdentifiers (myMethodIdentifierNames, NUM_METHOD_IDENTIFIERS, myMethodIdentifiers); |
| }; |
| |
| bool myHasProperty (NPClass *theClass, NPIdentifier name) |
| { |
| int i; |
| for (i = 0; i < NUM_PROPERTY_IDENTIFIERS; i++) { |
| if (name == myPropertyIdentifiers[i]){ |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool myHasMethod (NPClass *theClass, NPIdentifier name) |
| { |
| int i; |
| for (i = 0; i < NUM_METHOD_IDENTIFIERS; i++) { |
| if (name == myMethodIdentifiers[i]){ |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| |
| void logMessage (const NPVariant *message) |
| { |
| if (message->type == NPVariantStringType) { |
| char msgBuf[1024]; |
| strncpy (msgBuf, message->value.stringValue.UTF8Characters, message->value.stringValue.UTF8Length); |
| msgBuf[message->value.stringValue.UTF8Length] = 0; |
| printf ("%s\n", msgBuf); |
| } |
| else if (message->type == NPVariantDoubleType) |
| printf ("%f\n", (float)message->value.doubleValue); |
| else if (message->type == NPVariantInt32Type) |
| printf ("%d\n", message->value.intValue); |
| else if (message->type == NPVariantObjectType) |
| printf ("%p\n", message->value.objectValue); |
| } |
| |
| void setDoubleValue (MyObject *obj, const NPVariant *variant) |
| { |
| if (!NPN_VariantToDouble (variant, &obj->doubleValue)) { |
| NPUTF8 *msg = "Attempt to set double value with invalid type."; |
| NPString aString; |
| aString.UTF8Characters = msg; |
| aString.UTF8Length = strlen (msg); |
| NPN_SetException ((NPObject *)obj, &aString); |
| } |
| } |
| |
| void setIntValue (MyObject *obj, const NPVariant *variant) |
| { |
| if (!NPN_VariantToInt32 (variant, &obj->intValue)) { |
| NPUTF8 *msg = "Attempt to set int value with invalid type."; |
| NPString aString; |
| aString.UTF8Characters = msg; |
| aString.UTF8Length = strlen (msg); |
| NPN_SetException ((NPObject *)obj, &aString); |
| } |
| } |
| |
| void setStringValue (MyObject *obj, const NPVariant *variant) |
| { |
| NPN_ReleaseVariantValue (&obj->stringValue); |
| NPN_InitializeVariantWithVariant (&obj->stringValue, variant); |
| } |
| |
| void setBooleanValue (MyObject *obj, const NPVariant *variant) |
| { |
| if (!NPN_VariantToBool (variant, (NPBool *)&obj->boolValue)) { |
| NPUTF8 *msg = "Attempt to set bool value with invalid type."; |
| NPString aString; |
| aString.UTF8Characters = msg; |
| aString.UTF8Length = strlen (msg); |
| NPN_SetException ((NPObject *)obj, &aString); |
| } |
| } |
| |
| void getDoubleValue (MyObject *obj, NPVariant *variant) |
| { |
| NPN_InitializeVariantWithDouble (variant, obj->doubleValue); |
| } |
| |
| void getIntValue (MyObject *obj, NPVariant *variant) |
| { |
| NPN_InitializeVariantWithInt32 (variant, obj->intValue); |
| } |
| |
| void getStringValue (MyObject *obj, NPVariant *variant) |
| { |
| NPN_InitializeVariantWithVariant (variant, &obj->stringValue); |
| } |
| |
| void getBooleanValue (MyObject *obj, NPVariant *variant) |
| { |
| NPN_InitializeVariantWithBool (variant, obj->boolValue); |
| } |
| |
| void myGetProperty (MyObject *obj, NPIdentifier name, NPVariant *variant) |
| { |
| if (name == myPropertyIdentifiers[ID_DOUBLE_VALUE]){ |
| getDoubleValue (obj, variant); |
| } |
| else if (name == myPropertyIdentifiers[ID_INT_VALUE]){ |
| getIntValue (obj, variant); |
| } |
| else if (name == myPropertyIdentifiers[ID_STRING_VALUE]){ |
| getStringValue (obj, variant); |
| } |
| else if (name == myPropertyIdentifiers[ID_BOOLEAN_VALUE]){ |
| getBooleanValue (obj, variant); |
| } |
| else if (name == myPropertyIdentifiers[ID_NULL_VALUE]){ |
| return NPN_InitializeVariantAsNull (variant); |
| } |
| else if (name == myPropertyIdentifiers[ID_UNDEFINED_VALUE]){ |
| return NPN_InitializeVariantAsUndefined (variant); |
| } |
| else |
| NPN_InitializeVariantAsUndefined(variant); |
| } |
| |
| void mySetProperty (MyObject *obj, NPIdentifier name, const NPVariant *variant) |
| { |
| if (name == myPropertyIdentifiers[ID_DOUBLE_VALUE]) { |
| setDoubleValue (obj, variant); |
| } |
| else if (name == myPropertyIdentifiers[ID_INT_VALUE]) { |
| setIntValue (obj, variant); |
| } |
| else if (name == myPropertyIdentifiers[ID_STRING_VALUE]) { |
| setStringValue (obj, variant); |
| } |
| else if (name == myPropertyIdentifiers[ID_BOOLEAN_VALUE]) { |
| setBooleanValue (obj, variant); |
| } |
| else if (name == myPropertyIdentifiers[ID_NULL_VALUE]) { |
| // Do nothing! |
| } |
| else if (name == myPropertyIdentifiers[ID_UNDEFINED_VALUE]) { |
| // Do nothing! |
| } |
| } |
| |
| void myInvoke (MyObject *obj, NPIdentifier name, NPVariant *args, unsigned argCount, NPVariant *result) |
| { |
| if (name == myMethodIdentifiers[ID_LOG_MESSAGE]) { |
| if (argCount == 1 && NPN_VariantIsString(&args[0])) |
| logMessage (&args[0]); |
| NPN_InitializeVariantAsVoid (result); |
| } |
| else if (name == myMethodIdentifiers[ID_SET_DOUBLE_VALUE]) { |
| if (argCount == 1 && NPN_VariantIsDouble (&args[0])) |
| setDoubleValue (obj, &args[0]); |
| NPN_InitializeVariantAsVoid (result); |
| } |
| else if (name == myMethodIdentifiers[ID_SET_INT_VALUE]) { |
| if (argCount == 1 && (NPN_VariantIsDouble (&args[0]) || NPN_VariantIsInt32 (&args[0]))) |
| setIntValue (obj, &args[0]); |
| NPN_InitializeVariantAsVoid (result); |
| } |
| else if (name == myMethodIdentifiers[ID_SET_STRING_VALUE]) { |
| if (argCount == 1 && NPN_VariantIsString (&args[0])) |
| setStringValue (obj, &args[0]); |
| NPN_InitializeVariantAsVoid (result); |
| } |
| else if (name == myMethodIdentifiers[ID_SET_BOOLEAN_VALUE]) { |
| if (argCount == 1 && NPN_VariantIsBool (&args[0])) |
| setBooleanValue (obj, &args[0]); |
| NPN_InitializeVariantAsVoid (result); |
| } |
| else if (name == myMethodIdentifiers[ID_GET_DOUBLE_VALUE]) { |
| getDoubleValue (obj, result); |
| } |
| else if (name == myMethodIdentifiers[ID_GET_INT_VALUE]) { |
| getIntValue (obj, result); |
| } |
| else if (name == myMethodIdentifiers[ID_GET_STRING_VALUE]) { |
| getStringValue (obj, result); |
| } |
| else if (name == myMethodIdentifiers[ID_GET_BOOLEAN_VALUE]) { |
| getBooleanValue (obj, result); |
| } |
| else |
| NPN_InitializeVariantAsUndefined (result); |
| } |
| |
| NPObject *myAllocate () |
| { |
| MyObject *newInstance = (MyObject *)malloc (sizeof(MyObject)); |
| |
| if (!identifiersInitialized) { |
| identifiersInitialized = true; |
| initializeIdentifiers(); |
| } |
| |
| |
| newInstance->doubleValue = 666.666; |
| newInstance->intValue = 1234; |
| newInstance->boolValue = true; |
| newInstance->stringValue.type = NPVariantType_String; |
| newInstance->stringValue.value.stringValue.UTF8Length = strlen ("Hello world"); |
| newInstance->stringValue.value.stringValue.UTF8Characters = strdup ("Hello world"); |
| |
| return (NPObject *)newInstance; |
| } |
| |
| void myInvalidate () |
| { |
| // Make sure we've released any remaining references to JavaScript objects. |
| } |
| |
| void myDeallocate (MyObject *obj) |
| { |
| free ((void *)obj); |
| } |
| |
| static NPClass _myFunctionPtrs = { |
| kNPClassStructVersionCurrent, |
| (NPAllocateFunctionPtr) myAllocate, |
| (NPDeallocateFunctionPtr) myDeallocate, |
| (NPInvalidateFunctionPtr) myInvalidate, |
| (NPHasMethodFunctionPtr) myHasMethod, |
| (NPInvokeFunctionPtr) myInvoke, |
| (NPHasPropertyFunctionPtr) myHasProperty, |
| (NPGetPropertyFunctionPtr) myGetProperty, |
| (NPSetPropertyFunctionPtr) mySetProperty, |
| }; |
| static NPClass *myFunctionPtrs = &_myFunctionPtrs; |
| |
| // -------------------------------------------------------- |
| |
| using namespace JSC; |
| using namespace JSC::Bindings; |
| |
| class GlobalImp : public ObjectImp { |
| public: |
| virtual String className() const { return "global"; } |
| }; |
| |
| #define BufferSize 200000 |
| static char code[BufferSize]; |
| |
| const char *readJavaScriptFromFile (const char *file) |
| { |
| FILE *f = fopen(file, "r"); |
| if (!f) { |
| fprintf(stderr, "Error opening %s.\n", file); |
| return 0; |
| } |
| |
| int num = fread(code, 1, BufferSize, f); |
| code[num] = '\0'; |
| if(num >= BufferSize) |
| fprintf(stderr, "Warning: File may have been too long.\n"); |
| |
| fclose(f); |
| |
| return code; |
| } |
| |
| int main(int argc, char **argv) |
| { |
| // expecting a filename |
| if (argc < 2) { |
| fprintf(stderr, "You have to specify at least one filename\n"); |
| return -1; |
| } |
| |
| bool ret = true; |
| { |
| JSLock lock; |
| |
| // create interpreter w/ global object |
| Object global(new GlobalImp()); |
| Interpreter interp; |
| interp.setGlobalObject(global); |
| JSGlobalObject* lexicalGlobalObject = interp.globalObject(); |
| |
| MyObject *myObject = (MyObject *)NPN_CreateObject (myFunctionPtrs); |
| |
| global.put(lexicalGlobalObject, Identifier::fromString(lexicalGlobalObject, "myInterface"_s), Instance::createRuntimeObject(Instance::CLanguage, (void *)myObject)); |
| |
| for (int i = 1; i < argc; i++) { |
| const char *code = readJavaScriptFromFile(argv[i]); |
| |
| if (code) { |
| // run |
| Completion comp(interp.evaluate(code)); |
| |
| if (comp.complType() == Throw) { |
| Value exVal = comp.value(); |
| String message = exVal.toWTFString(lexicalGlobalObject); |
| auto cstring = msg.ascii(); |
| const char* msg = cstring.data(); |
| int lineno = -1; |
| if (exVal.type() == ObjectType) { |
| Value lineVal = Object::dynamicCast(exVal).get(lexicalGlobalObject, Identifier::fromString(lexicalGlobalObject, "line"_s)); |
| if (lineVal.type() == NumberType) |
| lineno = int(lineVal.toNumber(lexicalGlobalObject)); |
| } |
| if (lineno != -1) |
| fprintf(stderr,"Exception, line %d: %s\n",lineno,msg); |
| else |
| fprintf(stderr,"Exception: %s\n",msg); |
| ret = false; |
| } |
| else if (comp.complType() == ReturnValue) { |
| char *msg = comp.value().toString(interp.globalObject()).ascii(); |
| fprintf(stderr,"Return value: %s\n",msg); |
| } |
| } |
| } |
| |
| NPN_ReleaseObject ((NPObject *)myObject); |
| |
| } // end block, so that Interpreter and global get deleted |
| |
| return ret ? 0 : 3; |
| } |