mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-09-21 12:30:16 +02:00
ba7f53c261
mozilla-573873-1.8.patch mozilla-liveconnect-1.9.2.13.patch mozilla-nsTArray.patch
747 lines
23 KiB
C
747 lines
23 KiB
C
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is Mozilla Communicator client code, released
|
|
* March 31, 1998.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
/* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
|
*
|
|
* It contains the native code implementation of JS's JavaClass class.
|
|
*
|
|
* A JavaClass is JavaScript's representation of a Java class.
|
|
* Its parent JS object is always a JavaPackage object. A JavaClass is not an
|
|
* exact reflection of Java's corresponding java.lang.Class object. Rather,
|
|
* the properties of a JavaClass are the static methods and properties of the
|
|
* corresponding Java class.
|
|
*
|
|
* Note that there is no runtime equivalent to the JavaClass class in Java.
|
|
* (Although there are instances of java.lang.String and there are static
|
|
* methods of java.lang.String that can be invoked, there's no such thing as
|
|
* a first-class object that can be referenced simply as "java.lang.String".)
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "jsj_private.h" /* LiveConnect internals */
|
|
#include "jscntxt.h" /* for error reporting */
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
JavaClass_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
|
{
|
|
char *name;
|
|
JSString *str;
|
|
|
|
JavaClassDescriptor *class_descriptor;
|
|
|
|
class_descriptor = JS_GetPrivate(cx, obj);
|
|
if (!class_descriptor)
|
|
return JS_FALSE;
|
|
|
|
switch(type) {
|
|
|
|
|
|
case JSTYPE_STRING:
|
|
/* Convert '/' to '.' so that it looks like Java language syntax. */
|
|
if (!class_descriptor->name)
|
|
break;
|
|
name = JS_smprintf("[JavaClass %s]", class_descriptor->name);
|
|
if (!name) {
|
|
JS_ReportOutOfMemory(cx);
|
|
return JS_FALSE;
|
|
}
|
|
|
|
str = JS_NewString(cx, name, strlen(name));
|
|
if (!str) {
|
|
free(name);
|
|
/* It's not necessary to call JS_ReportOutOfMemory(), as
|
|
JS_NewString() will do so on failure. */
|
|
return JS_FALSE;
|
|
}
|
|
|
|
*vp = STRING_TO_JSVAL(str);
|
|
return JS_TRUE;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return JS_TRUE;
|
|
}
|
|
|
|
static JSBool
|
|
lookup_static_member_by_id(JSContext *cx, JNIEnv *jEnv, JSObject *obj,
|
|
JavaClassDescriptor **class_descriptorp,
|
|
jsid id, JavaMemberDescriptor **memberp)
|
|
{
|
|
jsval idval;
|
|
JavaMemberDescriptor *member_descriptor;
|
|
const char *member_name;
|
|
JavaClassDescriptor *class_descriptor;
|
|
|
|
class_descriptor = JS_GetPrivate(cx, obj);
|
|
if (!class_descriptor) {
|
|
*class_descriptorp = NULL;
|
|
*memberp = NULL;
|
|
return JS_TRUE;
|
|
}
|
|
|
|
if (class_descriptorp)
|
|
*class_descriptorp = class_descriptor;
|
|
|
|
member_descriptor = jsj_LookupJavaStaticMemberDescriptorById(cx, jEnv, class_descriptor, id);
|
|
if (!member_descriptor) {
|
|
JS_IdToValue(cx, id, &idval);
|
|
if (!JSVAL_IS_STRING(idval)) {
|
|
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
|
|
JSJMSG_BAD_JCLASS_EXPR);
|
|
return JS_FALSE;
|
|
}
|
|
|
|
member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
|
|
|
|
/*
|
|
* See if the property looks like the explicit resolution of an
|
|
* overloaded method, e.g. "max(double,double)".
|
|
*/
|
|
member_descriptor =
|
|
jsj_ResolveExplicitMethod(cx, jEnv, class_descriptor, id, JS_TRUE);
|
|
if (member_descriptor)
|
|
goto done;
|
|
|
|
/* Why do we have to do this ? */
|
|
if (!strcmp(member_name, "prototype")) {
|
|
*memberp = NULL;
|
|
return JS_TRUE;
|
|
}
|
|
|
|
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
|
|
JSJMSG_MISSING_NAME,
|
|
class_descriptor->name, member_name);
|
|
return JS_FALSE;
|
|
}
|
|
|
|
done:
|
|
if (memberp)
|
|
*memberp = member_descriptor;
|
|
return JS_TRUE;
|
|
}
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
JavaClass_getPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
|
{
|
|
jsval idval;
|
|
jclass java_class;
|
|
const char *member_name;
|
|
JavaClassDescriptor *class_descriptor;
|
|
JavaMemberDescriptor *member_descriptor;
|
|
JNIEnv *jEnv;
|
|
JSJavaThreadState *jsj_env;
|
|
JSBool result;
|
|
|
|
/* printf("In JavaClass_getProperty\n"); */
|
|
|
|
/* Get the Java per-thread environment pointer for this JSContext */
|
|
jsj_env = jsj_EnterJava(cx, &jEnv);
|
|
if (!jEnv)
|
|
return JS_FALSE;
|
|
|
|
if (!lookup_static_member_by_id(cx, jEnv, obj, &class_descriptor, id, &member_descriptor)) {
|
|
jsj_ExitJava(jsj_env);
|
|
return JS_FALSE;
|
|
}
|
|
if (!member_descriptor) {
|
|
*vp = JSVAL_VOID;
|
|
jsj_ExitJava(jsj_env);
|
|
return JS_TRUE;
|
|
}
|
|
|
|
java_class = class_descriptor->java_class;
|
|
|
|
if (member_descriptor->field) {
|
|
if (!member_descriptor->methods) {
|
|
result = jsj_GetJavaFieldValue(cx, jEnv, member_descriptor->field, java_class, vp);
|
|
jsj_ExitJava(jsj_env);
|
|
return result;
|
|
} else {
|
|
JS_ASSERT(0);
|
|
}
|
|
} else {
|
|
JSFunction *function;
|
|
|
|
/* TODO - eliminate JSFUN_BOUND_METHOD */
|
|
if (member_descriptor->methods->is_alias) {
|
|
/* If this is an explicit resolution of an overloaded method,
|
|
use the fully-qualified method name as the name of the
|
|
resulting JS function, i.e. "myMethod(int,long)" */
|
|
JS_IdToValue(cx, id, &idval);
|
|
member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
|
|
} else {
|
|
/* Either not explicit resolution of overloaded method or
|
|
explicit resolution was unnecessary because method was
|
|
not overloaded. */
|
|
member_name = member_descriptor->name;
|
|
}
|
|
function = JS_NewFunction(cx, jsj_JavaStaticMethodWrapper, 0,
|
|
JSFUN_BOUND_METHOD, obj, member_name);
|
|
if (!function) {
|
|
jsj_ExitJava(jsj_env);
|
|
return JS_FALSE;
|
|
}
|
|
|
|
*vp = OBJECT_TO_JSVAL(JS_GetFunctionObject(function));
|
|
}
|
|
|
|
jsj_ExitJava(jsj_env);
|
|
return JS_TRUE;
|
|
}
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
JavaClass_setPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
|
{
|
|
jclass java_class;
|
|
const char *member_name;
|
|
JavaClassDescriptor *class_descriptor;
|
|
JavaMemberDescriptor *member_descriptor;
|
|
jsval idval;
|
|
JNIEnv *jEnv;
|
|
JSJavaThreadState *jsj_env;
|
|
JSBool result;
|
|
|
|
/* printf("In JavaClass_setProperty\n"); */
|
|
|
|
/* Get the Java per-thread environment pointer for this JSContext */
|
|
jsj_env = jsj_EnterJava(cx, &jEnv);
|
|
if (!jEnv)
|
|
return JS_FALSE;
|
|
|
|
if (!lookup_static_member_by_id(cx, jEnv, obj, &class_descriptor, id, &member_descriptor)) {
|
|
jsj_ExitJava(jsj_env);
|
|
return JS_FALSE;
|
|
}
|
|
|
|
/* Check for the case where there is a method with the given name, but no field
|
|
with that name */
|
|
if (!member_descriptor->field)
|
|
goto no_such_field;
|
|
|
|
/* Silently fail if field value is final (immutable), as required by ECMA spec */
|
|
if (member_descriptor->field->modifiers & ACC_FINAL) {
|
|
jsj_ExitJava(jsj_env);
|
|
return JS_TRUE;
|
|
}
|
|
|
|
java_class = class_descriptor->java_class;
|
|
result = jsj_SetJavaFieldValue(cx, jEnv, member_descriptor->field, java_class, *vp);
|
|
jsj_ExitJava(jsj_env);
|
|
return result;
|
|
|
|
no_such_field:
|
|
JS_IdToValue(cx, id, &idval);
|
|
member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
|
|
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
|
|
JSJMSG_MISSING_STATIC,
|
|
member_name, class_descriptor->name);
|
|
jsj_ExitJava(jsj_env);
|
|
return JS_FALSE;
|
|
}
|
|
|
|
/*
|
|
* Free the private native data associated with the JavaPackage object.
|
|
*/
|
|
JS_STATIC_DLL_CALLBACK(void)
|
|
JavaClass_finalize(JSContext *cx, JSObject *obj)
|
|
{
|
|
JNIEnv *jEnv;
|
|
JSJavaThreadState *jsj_env;
|
|
|
|
JavaClassDescriptor *class_descriptor = JS_GetPrivate(cx, obj);
|
|
if (!class_descriptor)
|
|
return;
|
|
|
|
/* Get the Java per-thread environment pointer for this JSContext */
|
|
jsj_env = jsj_EnterJava(cx, &jEnv);
|
|
if (!jEnv)
|
|
return;
|
|
|
|
/* printf("Finalizing %s\n", class_descriptor->name); */
|
|
jsj_ReleaseJavaClassDescriptor(cx, jEnv, class_descriptor);
|
|
jsj_ExitJava(jsj_env);
|
|
}
|
|
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
JavaClass_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
|
|
JSObject **objp, JSProperty **propp)
|
|
{
|
|
JNIEnv *jEnv;
|
|
JSErrorReporter old_reporter;
|
|
JSJavaThreadState *jsj_env;
|
|
|
|
/* printf("In JavaClass_lookupProperty()\n"); */
|
|
|
|
/* Get the Java per-thread environment pointer for this JSContext */
|
|
jsj_env = jsj_EnterJava(cx, &jEnv);
|
|
if (!jEnv)
|
|
return JS_FALSE;
|
|
|
|
old_reporter = JS_SetErrorReporter(cx, NULL);
|
|
if (lookup_static_member_by_id(cx, jEnv, obj, NULL, id, NULL)) {
|
|
*objp = obj;
|
|
*propp = (JSProperty*)1;
|
|
js_SetObjectWeakRoot(cx, obj);
|
|
} else {
|
|
*objp = NULL;
|
|
*propp = NULL;
|
|
}
|
|
|
|
JS_SetErrorReporter(cx, old_reporter);
|
|
jsj_ExitJava(jsj_env);
|
|
return JS_TRUE;
|
|
}
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
JavaClass_defineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
|
|
JSPropertyOp getter, JSPropertyOp setter,
|
|
uintN attrs, JSProperty **propp)
|
|
{
|
|
JavaClassDescriptor *class_descriptor;
|
|
|
|
class_descriptor = JS_GetPrivate(cx, obj);
|
|
|
|
/* Check for prototype JavaClass object */
|
|
if (!class_descriptor)
|
|
return JS_TRUE;
|
|
|
|
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
|
|
JSJMSG_JCLASS_PROP_DEFINE);
|
|
return JS_FALSE;
|
|
}
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
JavaClass_getAttributes(JSContext *cx, JSObject *obj, jsid id,
|
|
JSProperty *prop, uintN *attrsp)
|
|
{
|
|
/* We don't maintain JS property attributes for Java class members */
|
|
*attrsp = JSPROP_PERMANENT|JSPROP_ENUMERATE;
|
|
return JS_FALSE;
|
|
}
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
JavaClass_setAttributes(JSContext *cx, JSObject *obj, jsid id,
|
|
JSProperty *prop, uintN *attrsp)
|
|
{
|
|
/* We don't maintain JS property attributes for Java class members */
|
|
if (*attrsp != (JSPROP_PERMANENT|JSPROP_ENUMERATE)) {
|
|
JS_ASSERT(0);
|
|
return JS_FALSE;
|
|
}
|
|
|
|
/* Silently ignore all setAttribute attempts */
|
|
return JS_TRUE;
|
|
}
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
JavaClass_deleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
|
{
|
|
JSVersion version = JS_GetVersion(cx);
|
|
|
|
*vp = JSVAL_FALSE;
|
|
|
|
if (!JSVERSION_IS_ECMA(version)) {
|
|
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
|
|
JSJMSG_JCLASS_PROP_DELETE);
|
|
return JS_FALSE;
|
|
} else {
|
|
/* Attempts to delete permanent properties are silently ignored
|
|
by ECMAScript. */
|
|
return JS_TRUE;
|
|
}
|
|
}
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
JavaClass_defaultValue(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
|
{
|
|
/* printf("In JavaClass_defaultValue()\n"); */
|
|
return JavaClass_convert(cx, obj, JSTYPE_STRING, vp);
|
|
}
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
JavaClass_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
|
|
jsval *statep, jsid *idp)
|
|
{
|
|
JavaMemberDescriptor *member_descriptor;
|
|
JavaClassDescriptor *class_descriptor;
|
|
JNIEnv *jEnv;
|
|
JSJavaThreadState *jsj_env;
|
|
|
|
class_descriptor = JS_GetPrivate(cx, obj);
|
|
|
|
/* Check for prototype JavaClass object */
|
|
if (!class_descriptor) {
|
|
*statep = JSVAL_NULL;
|
|
if (idp)
|
|
*idp = INT_TO_JSVAL(0);
|
|
return JS_TRUE;
|
|
}
|
|
|
|
switch(enum_op) {
|
|
case JSENUMERATE_INIT:
|
|
/* Get the Java per-thread environment pointer for this JSContext */
|
|
jsj_env = jsj_EnterJava(cx, &jEnv);
|
|
if (!jEnv)
|
|
return JS_FALSE;
|
|
member_descriptor = jsj_GetClassStaticMembers(cx, jEnv, class_descriptor);
|
|
*statep = PRIVATE_TO_JSVAL(member_descriptor);
|
|
if (idp)
|
|
*idp = INT_TO_JSVAL(class_descriptor->num_instance_members);
|
|
jsj_ExitJava(jsj_env);
|
|
return JS_TRUE;
|
|
|
|
case JSENUMERATE_NEXT:
|
|
member_descriptor = JSVAL_TO_PRIVATE(*statep);
|
|
if (member_descriptor) {
|
|
|
|
/* Don't enumerate explicit-signature methods, i.e. enumerate toValue,
|
|
but not toValue(int), toValue(double), etc. */
|
|
while (member_descriptor->methods && member_descriptor->methods->is_alias) {
|
|
member_descriptor = member_descriptor->next;
|
|
if (!member_descriptor) {
|
|
*statep = JSVAL_NULL;
|
|
return JS_TRUE;
|
|
}
|
|
}
|
|
|
|
*idp = member_descriptor->id;
|
|
*statep = PRIVATE_TO_JSVAL(member_descriptor->next);
|
|
return JS_TRUE;
|
|
}
|
|
/* Fall through ... */
|
|
|
|
case JSENUMERATE_DESTROY:
|
|
*statep = JSVAL_NULL;
|
|
return JS_TRUE;
|
|
|
|
default:
|
|
JS_ASSERT(0);
|
|
return JS_FALSE;
|
|
}
|
|
}
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
JavaClass_checkAccess(JSContext *cx, JSObject *obj, jsid id,
|
|
JSAccessMode mode, jsval *vp, uintN *attrsp)
|
|
{
|
|
switch (mode) {
|
|
case JSACC_WATCH:
|
|
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
|
|
JSJMSG_JCLASS_PROP_WATCH);
|
|
return JS_FALSE;
|
|
|
|
case JSACC_IMPORT:
|
|
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
|
|
JSJMSG_JCLASS_PROP_EXPORT);
|
|
return JS_FALSE;
|
|
|
|
default:
|
|
return JS_TRUE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Implement the JavaScript instanceof operator for JavaClass objects by using
|
|
* the equivalent Java instanceof operation.
|
|
*/
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
JavaClass_hasInstance(JSContext *cx, JSObject *obj, jsval candidate_jsval,
|
|
JSBool *has_instancep)
|
|
{
|
|
JavaClassDescriptor *class_descriptor;
|
|
JavaObjectWrapper *java_wrapper;
|
|
JSClass *js_class;
|
|
JSBool has_instance;
|
|
JSObject *candidate_obj;
|
|
jclass java_class;
|
|
jobject java_obj;
|
|
JNIEnv *jEnv;
|
|
JSJavaThreadState *jsj_env;
|
|
|
|
has_instance = JS_FALSE;
|
|
class_descriptor = JS_GetPrivate(cx, obj);
|
|
if (!class_descriptor) {
|
|
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
|
|
JSJMSG_BAD_OP_JCLASS);
|
|
return JS_FALSE;
|
|
}
|
|
|
|
/*
|
|
* Make sure that the thing to the left of the instanceof operator is a
|
|
* Java object.
|
|
*/
|
|
if (!JSVAL_IS_OBJECT(candidate_jsval))
|
|
goto done;
|
|
candidate_obj = JSVAL_TO_OBJECT(candidate_jsval);
|
|
#ifdef JS_THREADSAFE
|
|
js_class = JS_GetClass(cx, candidate_obj);
|
|
#else
|
|
js_class = JS_GetClass(candidate_obj);
|
|
#endif
|
|
if ((js_class != &JavaObject_class) && (js_class != &JavaArray_class))
|
|
goto done;
|
|
|
|
java_class = class_descriptor->java_class;
|
|
java_wrapper = JS_GetPrivate(cx, candidate_obj);
|
|
if (!java_wrapper) {
|
|
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
|
|
JSJMSG_BAD_OP_PROTO);
|
|
return JS_FALSE;
|
|
}
|
|
java_obj = java_wrapper->java_obj;
|
|
/* Get JNI pointer */
|
|
jsj_env = jsj_EnterJava(cx, &jEnv);
|
|
has_instance = (*jEnv)->IsInstanceOf(jEnv, java_obj, java_class);
|
|
jsj_ExitJava(jsj_env);
|
|
|
|
done:
|
|
*has_instancep = has_instance;
|
|
return JS_TRUE;
|
|
}
|
|
|
|
JSObjectOps JavaClass_ops = {
|
|
/* Mandatory non-null function pointer members. */
|
|
jsj_wrapper_newObjectMap, /* newObjectMap */
|
|
jsj_wrapper_destroyObjectMap, /* destroyObjectMap */
|
|
JavaClass_lookupProperty,
|
|
JavaClass_defineProperty,
|
|
JavaClass_getPropertyById, /* getProperty */
|
|
JavaClass_setPropertyById, /* setProperty */
|
|
JavaClass_getAttributes,
|
|
JavaClass_setAttributes,
|
|
JavaClass_deleteProperty,
|
|
JavaClass_defaultValue,
|
|
JavaClass_newEnumerate,
|
|
JavaClass_checkAccess,
|
|
|
|
/* Optionally non-null members start here. */
|
|
NULL, /* thisObject */
|
|
NULL, /* dropProperty */
|
|
jsj_JavaConstructorWrapper, /* call */
|
|
jsj_JavaConstructorWrapper, /* construct */
|
|
NULL, /* xdrObject */
|
|
JavaClass_hasInstance, /* hasInstance */
|
|
NULL, /* setProto */
|
|
NULL, /* setParent */
|
|
NULL, /* mark */
|
|
NULL, /* clear */
|
|
jsj_wrapper_getRequiredSlot, /* getRequiredSlot */
|
|
jsj_wrapper_setRequiredSlot /* setRequiredSlot */
|
|
};
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSObjectOps *)
|
|
JavaClass_getObjectOps(JSContext *cx, JSClass *clazz)
|
|
{
|
|
return &JavaClass_ops;
|
|
}
|
|
|
|
JSClass JavaClass_class = {
|
|
"JavaClass", JSCLASS_HAS_PRIVATE,
|
|
NULL, NULL, NULL, NULL,
|
|
NULL, NULL, JavaClass_convert, JavaClass_finalize,
|
|
|
|
/* Optionally non-null members start here. */
|
|
JavaClass_getObjectOps,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
};
|
|
|
|
static JSObject *
|
|
jsj_new_JavaClass(JSContext *cx, JNIEnv *jEnv, JSObject* parent_obj,
|
|
JavaClassDescriptor *class_descriptor)
|
|
{
|
|
JSObject *JavaClass_obj;
|
|
|
|
JavaClass_obj = JS_NewObject(cx, &JavaClass_class, 0, parent_obj);
|
|
if (!JavaClass_obj)
|
|
return NULL;
|
|
|
|
JS_SetPrivate(cx, JavaClass_obj, (void *)class_descriptor);
|
|
|
|
#ifdef DEBUG
|
|
/* printf("JavaClass \'%s\' created\n", class_descriptor->name); */
|
|
#endif
|
|
|
|
return JavaClass_obj;
|
|
}
|
|
|
|
JSObject *
|
|
jsj_define_JavaClass(JSContext *cx, JNIEnv *jEnv, JSObject* parent_obj,
|
|
const char *simple_class_name,
|
|
jclass java_class)
|
|
{
|
|
JavaClassDescriptor *class_descriptor;
|
|
JSObject *JavaClass_obj;
|
|
|
|
class_descriptor = jsj_GetJavaClassDescriptor(cx, jEnv, java_class);
|
|
if (!class_descriptor)
|
|
return NULL;
|
|
|
|
JavaClass_obj = jsj_new_JavaClass(cx, jEnv, parent_obj, class_descriptor);
|
|
if (!JavaClass_obj)
|
|
return NULL;
|
|
|
|
if (!JS_DefineProperty(cx, parent_obj, simple_class_name,
|
|
OBJECT_TO_JSVAL(JavaClass_obj), 0, 0,
|
|
JSPROP_PERMANENT|JSPROP_READONLY|JSPROP_ENUMERATE))
|
|
return NULL;
|
|
return JavaClass_obj;
|
|
}
|
|
|
|
|
|
/*
|
|
* The getClass() native JS method is defined as a property of the global
|
|
* object. Given a JavaObject it returns the corresponding JavaClass. This
|
|
* is useful for accessing static methods and fields.
|
|
*
|
|
* js> getClass(new java.lang.String("foo"))
|
|
* [JavaClass java.lang.String]
|
|
*/
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
getClass(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|
{
|
|
JSObject *obj_arg, *JavaClass_obj;
|
|
JavaObjectWrapper *java_wrapper;
|
|
JavaClassDescriptor *class_descriptor;
|
|
JNIEnv *jEnv;
|
|
JSJavaThreadState *jsj_env;
|
|
|
|
if (argc != 1 ||
|
|
!JSVAL_IS_OBJECT(argv[0]) ||
|
|
!(obj_arg = JSVAL_TO_OBJECT(argv[0])) ||
|
|
(!JS_InstanceOf(cx, obj_arg, &JavaObject_class, 0) &&
|
|
!JS_InstanceOf(cx, obj_arg, &JavaArray_class, 0))) {
|
|
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
|
|
JSJMSG_NEED_JOBJECT_ARG);
|
|
return JS_FALSE;
|
|
}
|
|
|
|
java_wrapper = JS_GetPrivate(cx, obj_arg);
|
|
if (!java_wrapper) {
|
|
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
|
|
JSJMSG_PROTO_GETCLASS);
|
|
return JS_FALSE;
|
|
}
|
|
|
|
jsj_env = jsj_EnterJava(cx, &jEnv);
|
|
if (!jEnv)
|
|
return JS_FALSE;
|
|
|
|
class_descriptor = java_wrapper->class_descriptor;
|
|
|
|
JavaClass_obj = jsj_new_JavaClass(cx, jEnv, NULL, class_descriptor);
|
|
if (!JavaClass_obj) {
|
|
jsj_ExitJava(jsj_env);
|
|
return JS_FALSE;
|
|
}
|
|
|
|
*rval = OBJECT_TO_JSVAL(JavaClass_obj);
|
|
jsj_ExitJava(jsj_env);
|
|
return JS_TRUE;
|
|
}
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
JavaClass_construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|
{
|
|
JSObject *obj_arg, *JavaClass_obj;
|
|
JavaObjectWrapper *java_wrapper;
|
|
JavaClassDescriptor *class_descriptor;
|
|
JNIEnv *jEnv;
|
|
JSJavaThreadState *jsj_env;
|
|
|
|
if (argc != 1 ||
|
|
!JSVAL_IS_OBJECT(argv[0]) ||
|
|
!(obj_arg = JSVAL_TO_OBJECT(argv[0])) ||
|
|
!JS_InstanceOf(cx, obj_arg, &JavaObject_class, 0) ||
|
|
((java_wrapper = JS_GetPrivate(cx, obj_arg)) == NULL)) {
|
|
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
|
|
JSJMSG_NEED_JCLASS_ARG);
|
|
return JS_FALSE;
|
|
}
|
|
|
|
jsj_env = jsj_EnterJava(cx, &jEnv);
|
|
if (!jEnv)
|
|
return JS_FALSE;
|
|
|
|
class_descriptor = java_wrapper->class_descriptor;
|
|
if (!(*jEnv)->IsSameObject(jEnv, class_descriptor->java_class, jlClass)) {
|
|
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
|
|
JSJMSG_NEED_JCLASS_ARG);
|
|
jsj_ExitJava(jsj_env);
|
|
return JS_FALSE;
|
|
}
|
|
|
|
class_descriptor = jsj_GetJavaClassDescriptor(cx, jEnv, java_wrapper->java_obj);
|
|
JavaClass_obj = jsj_new_JavaClass(cx, jEnv, NULL, class_descriptor);
|
|
if (!JavaClass_obj) {
|
|
jsj_ExitJava(jsj_env);
|
|
return JS_FALSE;
|
|
}
|
|
|
|
*rval = OBJECT_TO_JSVAL(JavaClass_obj);
|
|
jsj_ExitJava(jsj_env);
|
|
return JS_TRUE;
|
|
}
|
|
|
|
extern JS_IMPORT_DATA(JSObjectOps) js_ObjectOps;
|
|
|
|
JSBool
|
|
jsj_init_JavaClass(JSContext *cx, JSObject *global_obj)
|
|
{
|
|
/* Define JavaClass class */
|
|
if (!JS_InitClass(cx, global_obj, 0, &JavaClass_class, JavaClass_construct, 0, 0, 0, 0, 0))
|
|
return JS_FALSE;
|
|
|
|
if (!JS_DefineFunction(cx, global_obj, "getClass", getClass, 0,
|
|
JSPROP_READONLY))
|
|
return JS_FALSE;
|
|
|
|
return jsj_InitJavaClassReflectionsTable();
|
|
}
|
|
|