422 lines
13 KiB
C++
422 lines
13 KiB
C++
/*
|
|
* 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"), 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"));
|
|
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;
|
|
}
|