mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 12:37:37 +00:00
626 lines
16 KiB
C
626 lines
16 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
/* ** */
|
|
/* FIXME remove when pure JRI if possible */
|
|
#include "oobj.h"
|
|
#include "interpreter.h"
|
|
#include "tree.h"
|
|
|
|
#include "jsapi.h"
|
|
#include "jsjava.h"
|
|
#include "jscntxt.h" /* for cx->savedErrors */
|
|
|
|
#include "jri.h"
|
|
|
|
#include "prmon.h" /* for PR_XLock and PR_XUnlock */
|
|
#include "prprf.h" /* for PR_snprintf */
|
|
#include "prthread.h"
|
|
#include "prlog.h"
|
|
|
|
#define IMPLEMENT_netscape_javascript_JSObject
|
|
#include "netscape_javascript_JSObject.h"
|
|
#ifndef XP_MAC
|
|
#include "netscape_javascript_JSException.h"
|
|
#else
|
|
#include "n_javascript_JSException.h"
|
|
#endif
|
|
|
|
|
|
#ifdef NSPR20
|
|
extern PRLogModuleInfo* Moja;
|
|
#define debug PR_LOG_DEBUG
|
|
#endif /* NSPR20 */
|
|
|
|
#define JAVA_JS_STACK_SIZE 8192
|
|
|
|
typedef struct {
|
|
JSErrorReporter errReporter;
|
|
} JSSavedState;
|
|
|
|
static void
|
|
js_throwJSException(JRIEnv *env, char *detail)
|
|
{
|
|
#ifdef JAVA
|
|
struct java_lang_String* message =
|
|
JRI_NewStringPlatform(env,
|
|
(const jbyte *) detail,
|
|
(jint) strlen(detail),
|
|
(const jbyte *) NULL,
|
|
(jint) 0);
|
|
struct netscape_javascript_JSException* exc =
|
|
netscape_javascript_JSException_new_1(env,
|
|
class_netscape_javascript_JSException(env),
|
|
/*Java_getGlobalRef(env, js_JSExceptionClass),*/
|
|
message);
|
|
|
|
JRI_Throw(env, (struct java_lang_Throwable*)exc);
|
|
#endif /* JAVA */
|
|
}
|
|
|
|
/***********************************************************************/
|
|
|
|
static bool_t
|
|
enterJS(JRIEnv *env,
|
|
struct netscape_javascript_JSObject* self,
|
|
JSContext **cxp, JSObject **jsop, JSSavedState *saved)
|
|
{
|
|
#ifndef JAVA
|
|
return JS_FALSE;
|
|
#else
|
|
char *err;
|
|
|
|
JSJ_EnterJS();
|
|
|
|
/* check the internal pointer for null while holding the
|
|
* js lock to deal with shutdown issues */
|
|
if (jsop &&
|
|
(! self ||
|
|
! (*jsop = (JSObject *)
|
|
get_netscape_javascript_JSObject_internal(env, self)))) {
|
|
|
|
/* FIXME use a better exception */
|
|
JRI_ThrowNew(env, JRI_FindClass(env, "java/lang/Exception"),
|
|
"not a JavaScript object");
|
|
JSJ_ExitJS();
|
|
return FALSE;
|
|
}
|
|
|
|
/* PR_LOG(Moja, debug, ("clearing exceptions in ee=0x%x", env)); */
|
|
|
|
exceptionClear((ExecEnv *)env);
|
|
|
|
if (! (*cxp = JSJ_CurrentContext(env, &err))) {
|
|
JSJ_ExitJS();
|
|
if (err) {
|
|
js_throwJSException(env, err);
|
|
free(err);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
jsj_ClearSavedErrors(*cxp);
|
|
|
|
saved->errReporter = JS_SetErrorReporter(*cxp, js_JavaErrorReporter);
|
|
return TRUE;
|
|
#endif
|
|
}
|
|
|
|
static bool_t
|
|
exitJS(JRIEnv *env,
|
|
struct netscape_javascript_JSObject* self,
|
|
JSContext *cx, JSObject *jso, JSSavedState *saved)
|
|
{
|
|
#ifndef JAVA
|
|
return JS_FALSE;
|
|
#else
|
|
/* restore saved info */
|
|
JS_SetErrorReporter(cx, saved->errReporter);
|
|
|
|
js_JSErrorToJException(cx, (ExecEnv*)env);
|
|
|
|
JSJ_ExitJS();
|
|
|
|
if (exceptionOccurred((ExecEnv*)env))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
#endif
|
|
}
|
|
|
|
/***********************************************************************/
|
|
|
|
JRI_PUBLIC_API(struct java_lang_Object *)
|
|
native_netscape_javascript_JSObject_getMember(
|
|
JRIEnv* env,
|
|
struct netscape_javascript_JSObject* self,
|
|
struct java_lang_String *name)
|
|
{
|
|
#ifndef JAVA
|
|
return NULL;
|
|
#else
|
|
JSContext *cx;
|
|
JSObject *jso;
|
|
JSSavedState saved;
|
|
const char *cstr;
|
|
struct java_lang_Object *member;
|
|
jsval val;
|
|
int cost = 0;
|
|
|
|
if (!enterJS(env, self, &cx, &jso, &saved))
|
|
return NULL;
|
|
|
|
if (! name ||
|
|
! (cstr = JRI_GetStringPlatformChars(env, name,
|
|
NULL, 0))) {
|
|
|
|
/* XXX - temporarily replace arguments so we can compile
|
|
(const jbyte *) cx->charSetName,
|
|
(jint) cx->charSetNameLength))) {
|
|
*/
|
|
|
|
/* FIXME this should be an error of some sort */
|
|
js_throwJSException(env, "illegal member name");
|
|
member = NULL;
|
|
goto do_exit;
|
|
}
|
|
|
|
if (! JS_GetProperty(cx, jso, cstr, &val) ||
|
|
! js_convertJSValueToJObject(/*FIXME*/(HObject**)&member, cx, val,
|
|
0, 0, JS_FALSE, &cost))
|
|
member = NULL;
|
|
|
|
do_exit:
|
|
if (!exitJS(env, self, cx, jso, &saved))
|
|
return NULL;
|
|
|
|
return member;
|
|
#endif
|
|
}
|
|
|
|
/***********************************************************************/
|
|
|
|
/* public native getSlot(I)Ljava/lang/Object; */
|
|
JRI_PUBLIC_API(struct java_lang_Object *)
|
|
native_netscape_javascript_JSObject_getSlot(
|
|
JRIEnv* env,
|
|
struct netscape_javascript_JSObject* self,
|
|
jint slot)
|
|
{
|
|
#ifndef JAVA
|
|
return NULL;
|
|
#else
|
|
JSContext *cx;
|
|
JSObject *jso;
|
|
JSSavedState saved;
|
|
struct java_lang_Object *member;
|
|
jsval val;
|
|
int cost = 0;
|
|
|
|
if (!enterJS(env, self, &cx, &jso, &saved))
|
|
return NULL;
|
|
|
|
if (! JS_GetElement(cx, jso, slot, &val) ||
|
|
! js_convertJSValueToJObject(/*FIXME*/(HObject**)&member, cx, val,
|
|
0, 0, JS_FALSE, &cost))
|
|
member = NULL;
|
|
|
|
if (!exitJS(env, self, cx, jso, &saved))
|
|
return NULL;
|
|
|
|
return member;
|
|
#endif
|
|
}
|
|
|
|
/***********************************************************************/
|
|
|
|
JRI_PUBLIC_API(void)
|
|
native_netscape_javascript_JSObject_setMember(
|
|
JRIEnv* env,
|
|
struct netscape_javascript_JSObject* self,
|
|
struct java_lang_String *name,
|
|
struct java_lang_Object *value)
|
|
{
|
|
#ifdef JAVA
|
|
JSContext *cx;
|
|
JSObject *jso;
|
|
JSSavedState saved;
|
|
const char *cstr;
|
|
jsval val;
|
|
|
|
if (!enterJS(env, self, &cx, &jso, &saved))
|
|
return;
|
|
|
|
if (! name ||
|
|
! (cstr = JRI_GetStringPlatformChars(env, name,
|
|
NULL, 0))) {
|
|
|
|
/* XXX - temporarily replace arguments so we can compile
|
|
(const jbyte *) cx->charSetName,
|
|
(jint) cx->charSetNameLength))) {
|
|
*/
|
|
|
|
js_throwJSException(env, "illegal member name");
|
|
goto do_exit;
|
|
}
|
|
|
|
if (js_convertJObjectToJSValue(cx, &val, (HObject *)value) &&
|
|
JS_SetProperty(cx, jso, cstr, &val)) {
|
|
}
|
|
|
|
/* PR_LOG(Moja, debug,
|
|
("JSObject.setMember(%s, 0x%x)\n", cstr, value)); */
|
|
|
|
do_exit:
|
|
exitJS(env, self, cx, jso, &saved);
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
/***********************************************************************/
|
|
|
|
JRI_PUBLIC_API(void)
|
|
native_netscape_javascript_JSObject_setSlot(
|
|
JRIEnv* env,
|
|
struct netscape_javascript_JSObject* self,
|
|
jint slot,
|
|
struct java_lang_Object *value)
|
|
{
|
|
#ifdef JAVA
|
|
JSContext *cx;
|
|
JSObject *jso;
|
|
JSSavedState saved;
|
|
jsval val;
|
|
|
|
if (!enterJS(env, self, &cx, &jso, &saved))
|
|
return;
|
|
|
|
if (js_convertJObjectToJSValue(cx, &val, (HObject *)value) &&
|
|
JS_SetElement(cx, jso, slot, &val)) {
|
|
}
|
|
|
|
/* PR_LOG(Moja, debug,
|
|
("JSObject.setSlot(%d, 0x%x)\n", slot, value)); */
|
|
|
|
exitJS(env, self, cx, jso, &saved);
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
/***********************************************************************/
|
|
|
|
JRI_PUBLIC_API(void)
|
|
native_netscape_javascript_JSObject_removeMember(
|
|
JRIEnv* env,
|
|
struct netscape_javascript_JSObject* self,
|
|
struct java_lang_String * name)
|
|
{
|
|
JSContext *cx;
|
|
JSObject *jso;
|
|
JSSavedState saved;
|
|
#ifdef JAVA /* only referenced if defined */
|
|
const char *cstr;
|
|
#endif
|
|
|
|
if (!enterJS(env, self, &cx, &jso, &saved))
|
|
return;
|
|
#ifdef JAVA
|
|
if (! name ||
|
|
! (cstr = JRI_GetStringPlatformChars(env, name,
|
|
NULL, 0))) {
|
|
|
|
/* XXX - temporarily replace arguments so we can compile
|
|
(const jbyte *) cx->charSetName,
|
|
(jint) cx->charSetNameLength);
|
|
*/
|
|
/* FIXME this should be an error of some sort */
|
|
js_throwJSException(env, "illegal member name");
|
|
goto do_exit;
|
|
}
|
|
|
|
JS_DeleteProperty(cx, jso, cstr);
|
|
#endif
|
|
|
|
/* PR_LOG(Moja, debug,
|
|
("JSObject.removeMember(%s)\n", cstr)); */
|
|
#ifdef JAVA /* only referenced if defined */
|
|
do_exit:
|
|
#endif
|
|
exitJS(env, self, cx, jso, &saved);
|
|
return;
|
|
}
|
|
|
|
/***********************************************************************/
|
|
|
|
JRI_PUBLIC_API(struct java_lang_Object *)
|
|
native_netscape_javascript_JSObject_call(
|
|
JRIEnv* env,
|
|
struct netscape_javascript_JSObject* self,
|
|
struct java_lang_String *method,
|
|
jobjectArray args)
|
|
{
|
|
#ifndef JAVA
|
|
return NULL;
|
|
#else
|
|
JSContext *cx;
|
|
JSObject *jso;
|
|
JSSavedState saved;
|
|
const char *cstr;
|
|
struct java_lang_Object *ret;
|
|
int total_argc, argc, i;
|
|
jsval *argv;
|
|
jsval rval;
|
|
int cost = 0;
|
|
|
|
if (!enterJS(env, self, &cx, &jso, &saved))
|
|
return NULL;
|
|
|
|
if (! method ||
|
|
! (cstr = JRI_GetStringPlatformChars(env, method,
|
|
NULL, 0))) {
|
|
|
|
/* XXX - temporarily replace arguments so we can compile
|
|
(const jbyte *) cx->charSetName,
|
|
(jint) cx->charSetNameLength))) {
|
|
*/
|
|
/* FIXME this should be an error of some sort */
|
|
js_throwJSException(env, "illegal member name");
|
|
ret = NULL;
|
|
goto do_exit;
|
|
}
|
|
|
|
if (args) {
|
|
total_argc = JRI_GetObjectArrayLength(env, args);
|
|
argv = sysMalloc(total_argc * sizeof(jsval));
|
|
} else {
|
|
total_argc = 0;
|
|
argv = 0;
|
|
}
|
|
|
|
for (argc = 0; argc < total_argc; argc++) {
|
|
jref arg = JRI_GetObjectArrayElement(env, args, argc);
|
|
|
|
if (!js_convertJObjectToJSValue(cx, argv+argc, (HObject*)arg))
|
|
goto cleanup_argv;
|
|
JS_AddRoot(cx, argv+argc);
|
|
}
|
|
|
|
if (! JS_CallFunctionName(cx, jso, cstr, argc, argv, &rval) ||
|
|
! js_convertJSValueToJObject((HObject **) &ret, cx, rval,
|
|
0, 0, JS_FALSE, &cost)) {
|
|
ret = NULL;
|
|
}
|
|
|
|
cleanup_argv:
|
|
for (i = 0; i < argc; i++)
|
|
JS_RemoveRoot(cx, argv+i);
|
|
sysFree(argv);
|
|
|
|
do_exit:
|
|
if (!exitJS(env, self, cx, jso, &saved))
|
|
return NULL;
|
|
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
/***********************************************************************/
|
|
|
|
JRI_PUBLIC_API(struct java_lang_Object *)
|
|
native_netscape_javascript_JSObject_eval(
|
|
JRIEnv* env,
|
|
struct netscape_javascript_JSObject* self,
|
|
struct java_lang_String *s)
|
|
{
|
|
#ifndef JAVA
|
|
return NULL;
|
|
#else
|
|
JSContext *cx;
|
|
JSObject *jso;
|
|
JSSavedState saved;
|
|
const char *cstr;
|
|
int cstrlen;
|
|
struct java_lang_Object *ret;
|
|
jsval rval;
|
|
int cost = 0;
|
|
JSPrincipals *principals;
|
|
char *codebase;
|
|
|
|
if (!enterJS(env, self, &cx, &jso, &saved))
|
|
return NULL;
|
|
|
|
if (! s ||
|
|
! (cstr = JRI_GetStringPlatformChars(env, s,
|
|
NULL, 0))) {
|
|
|
|
/* XXX - temporarily replace arguments so we can compile
|
|
(const jbyte *) cx->charSetName,
|
|
(jint) cx->charSetNameLength))) {
|
|
*/
|
|
/* FIXME this should be an error of some sort */
|
|
js_throwJSException(env, "illegal eval string");
|
|
ret = NULL;
|
|
goto do_exit;
|
|
}
|
|
|
|
/* subtract 1 for the NUL */
|
|
/*
|
|
* FIXME There is no JRI_GetStringPlatformLength (what a misnomer, if there
|
|
* were!), but JRI_GetStringPlatformChars does NUL-terminate the encoded
|
|
* string, so we trust that no charset encoding ever uses a NUL byte as
|
|
* part of a multibyte sequence and just call strlen.
|
|
*/
|
|
cstrlen = strlen(cstr);
|
|
|
|
principals = js_GetJSPrincipalsFromJavaCaller(cx, 0);
|
|
codebase = principals ? principals->codebase : NULL;
|
|
if (! JS_EvaluateScriptForPrincipals(cx, jso, principals, cstr, cstrlen,
|
|
codebase, 0, &rval) ||
|
|
! js_convertJSValueToJObject((HObject**)&ret, cx, rval,
|
|
0, 0, JS_FALSE, &cost)) {
|
|
ret = NULL;
|
|
}
|
|
|
|
do_exit:
|
|
if (!exitJS(env, self, cx, jso, &saved))
|
|
return NULL;
|
|
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
/***********************************************************************/
|
|
|
|
JRI_PUBLIC_API(void)
|
|
native_netscape_javascript_JSObject_finalize(
|
|
JRIEnv* env,
|
|
struct netscape_javascript_JSObject* self)
|
|
{
|
|
#ifdef JAVA
|
|
JSContext *cx;
|
|
JSObject *jso;
|
|
JSSavedState saved;
|
|
|
|
/* FIXME if enterJS fails here we have a memory leak! */
|
|
|
|
if (!enterJS(env, self, &cx, &jso, &saved))
|
|
return;
|
|
|
|
js_RemoveReflection(cx, jso);
|
|
|
|
if (!exitJS(env, self, cx, jso, &saved))
|
|
return;
|
|
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
/***********************************************************************/
|
|
|
|
JRI_PUBLIC_API(struct java_lang_String *)
|
|
native_netscape_javascript_JSObject_toString(
|
|
JRIEnv* env,
|
|
struct netscape_javascript_JSObject* self)
|
|
{
|
|
JSContext *cx;
|
|
JSObject *jso;
|
|
JSSavedState saved;
|
|
#ifdef JAVA /* only referenced if defined */
|
|
JSString *jsstr;
|
|
char *cstr;
|
|
#endif
|
|
struct java_lang_String *ret = NULL;
|
|
|
|
if (!enterJS(env, self, &cx, &jso, &saved))
|
|
return NULL;
|
|
|
|
#ifdef JAVA
|
|
if ((jsstr = JS_ValueToString(cx, OBJECT_TO_JSVAL(jso))) &&
|
|
(cstr = JS_GetStringBytes(jsstr))) {
|
|
ret = JRI_NewStringPlatform(env,
|
|
(const jbyte *) cstr,
|
|
(jint) JS_GetStringLength(jsstr),
|
|
NULL, 0);
|
|
|
|
/* XXX - temporarily replace arguments so we can compile
|
|
(const jbyte *) cx->charSetName,
|
|
(jint) cx->charSetNameLength);
|
|
*/
|
|
|
|
} else {
|
|
/* FIXME could grab the clazz name from the JSObject */
|
|
ret = JRI_NewStringPlatform(env,
|
|
(const jbyte *) "*JSObject*",
|
|
(jint) strlen("*JSObject*"),
|
|
NULL, 0);
|
|
|
|
/* XXX - temporarily replace arguments so we can compile
|
|
(const jbyte *) cx->charSetName,
|
|
(jint) cx->charSetNameLength);
|
|
*/
|
|
}
|
|
#endif
|
|
|
|
if (!exitJS(env, self, cx, jso, &saved))
|
|
return NULL;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************/
|
|
|
|
JRI_PUBLIC_API(struct netscape_javascript_JSObject*)
|
|
native_netscape_javascript_JSObject_getWindow(
|
|
JRIEnv* env,
|
|
struct java_lang_Class* clazz,
|
|
struct java_applet_Applet* hint)
|
|
{
|
|
#ifndef JAVA
|
|
return NULL;
|
|
#else
|
|
struct netscape_javascript_JSObject *ret = NULL;
|
|
JSContext *cx;
|
|
JSSavedState saved;
|
|
JSObject *jso;
|
|
|
|
if (!JSJ_IsEnabled()) {
|
|
js_throwJSException(env, "Java/JavaScript communication is disabled");
|
|
return 0;
|
|
}
|
|
|
|
if (!enterJS(env, NULL, &cx, NULL, &saved))
|
|
return NULL;
|
|
|
|
jso = JSJ_GetDefaultObject(env, (jobject) hint);
|
|
if (exceptionOccurred((ExecEnv *)env))
|
|
goto out;
|
|
|
|
ret = (struct netscape_javascript_JSObject *)
|
|
js_ReflectJSObjectToJObject(cx, jso);
|
|
|
|
out:
|
|
if (!exitJS(env, NULL, cx, NULL, &saved))
|
|
return NULL;
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
/***********************************************************************/
|
|
|
|
JRI_PUBLIC_API(void)
|
|
native_netscape_javascript_JSObject_initClass(
|
|
JRIEnv* env,
|
|
struct java_lang_Class* myClazz)
|
|
{
|
|
#ifdef JAVA
|
|
struct java_lang_Class* clazz;
|
|
/* this is to initialize the field lookup indices, and protect
|
|
* the classes from gc. */
|
|
|
|
clazz = use_netscape_javascript_JSObject(env);
|
|
MakeClassSticky((struct Hjava_lang_Class*)clazz);
|
|
|
|
clazz = use_netscape_javascript_JSException(env);
|
|
MakeClassSticky((struct Hjava_lang_Class*)clazz);
|
|
|
|
/* this does nothing if somebody else has already set
|
|
* stuff up (i.e. client or server) */
|
|
JSJ_InitStandalone();
|
|
#endif
|
|
}
|
|
|