1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is Mozilla Communicator client code, released
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 1998
22 * the Initial Developer. All Rights Reserved.
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
41 * This file is part of the Java-vendor-neutral implementation of LiveConnect
43 * It contains the definition of the JavaScript JavaArray class.
44 * Instances of JavaArray are used to reflect Java arrays.
50 #include "jsj_private.h" /* LiveConnect internals */
52 /* Shorthands for ASCII (7-bit) decimal and hex conversion. */
53 #define JS7_ISDEC(c) (((c) >= '0') && ((c) <= '9'))
54 #define JS7_UNDEC(c) ((c) - '0')
57 * Convert any jsval v to an integer jsval if ToString(v)
58 * contains a base-10 integer that fits into 31 bits.
62 try_convert_to_jsint(JSContext
*cx
, jsval idval
)
67 jsstr
= JS_ValueToString(cx
, idval
);
71 cp
= JS_GetStringChars(jsstr
);
73 jsuint index
= JS7_UNDEC(*cp
++);
77 while (JS7_ISDEC(*cp
)) {
85 (oldIndex
< (JSVAL_INT_MAX
/ 10) ||
86 (oldIndex
== (JSVAL_INT_MAX
/ 10) && c
< (JSVAL_INT_MAX
% 10)))) {
87 return INT_TO_JSVAL(index
);
95 access_java_array_element(JSContext
*cx
,
100 JSBool do_assignment
)
104 JavaClassDescriptor
*class_descriptor
;
105 JavaObjectWrapper
*java_wrapper
;
106 jsize array_length
, index
;
107 JavaSignature
*array_component_signature
;
109 /* printf("In JavaArray_getProperty\n"); */
111 java_wrapper
= JS_GetPrivate(cx
, obj
);
113 const char *property_name
;
114 if (JS_IdToValue(cx
, id
, &idval
) && JSVAL_IS_STRING(idval
) &&
115 (property_name
= JS_GetStringBytes(JSVAL_TO_STRING(idval
))) != NULL
) {
116 if (!strcmp(property_name
, "constructor")) {
122 JS_ReportErrorNumber(cx
, jsj_GetErrorMessage
, NULL
,
123 JSJMSG_BAD_OP_JARRAY
);
126 class_descriptor
= java_wrapper
->class_descriptor
;
127 java_array
= java_wrapper
->java_obj
;
129 JS_ASSERT(class_descriptor
->type
== JAVA_SIGNATURE_ARRAY
);
131 JS_IdToValue(cx
, id
, &idval
);
133 if (!JSVAL_IS_INT(idval
))
134 idval
= try_convert_to_jsint(cx
, idval
);
136 if (!JSVAL_IS_INT(idval
)) {
138 * Usually, properties of JavaArray objects are indexed by integers, but
139 * Java arrays also inherit all the methods of java.lang.Object, so a
140 * string-valued property is also possible.
142 if (JSVAL_IS_STRING(idval
)) {
143 const char *member_name
;
145 member_name
= JS_GetStringBytes(JSVAL_TO_STRING(idval
));
148 JSVersion version
= JS_GetVersion(cx
);
150 if (!JSVERSION_IS_ECMA(version
)) {
152 JS_ReportErrorNumber(cx
, jsj_GetErrorMessage
, NULL
,
153 JSJMSG_CANT_WRITE_JARRAY
, member_name
);
161 if (!strcmp(member_name
, "length")) {
162 array_length
= jsj_GetJavaArrayLength(cx
, jEnv
, java_array
);
163 if (array_length
< 0)
166 *vp
= INT_TO_JSVAL(array_length
);
170 /* Check to see if we're reflecting a Java array method */
171 return JavaObject_getPropertyById(cx
, obj
, id
, vp
);
175 JS_ReportErrorNumber(cx
, jsj_GetErrorMessage
, NULL
,
176 JSJMSG_BAD_INDEX_EXPR
);
180 index
= JSVAL_TO_INT(idval
);
183 array_length
= jsj_GetJavaArrayLength(cx
, jEnv
, java_array
);
184 if (array_length
< 0)
187 /* Just let Java throw an exception instead of checking array bounds here */
188 if (index
< 0 || index
>= array_length
) {
190 sprintf(numBuf
, "%d", index
);
191 JS_ReportErrorNumber(cx
, jsj_GetErrorMessage
, NULL
,
192 JSJMSG_BAD_JARRAY_INDEX
, numBuf
);
197 array_component_signature
= class_descriptor
->array_component_signature
;
203 return jsj_SetJavaArrayElement(cx
, jEnv
, java_array
, index
,
204 array_component_signature
, *vp
);
206 return jsj_GetJavaArrayElement(cx
, jEnv
, java_array
, index
,
207 array_component_signature
, vp
);
212 JavaArray_getPropertyById(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
215 JSJavaThreadState
*jsj_env
;
218 jsj_env
= jsj_EnterJava(cx
, &jEnv
);
221 result
= access_java_array_element(cx
, jEnv
, obj
, id
, vp
, JS_FALSE
);
222 jsj_ExitJava(jsj_env
);
227 JavaArray_setPropertyById(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
230 JSJavaThreadState
*jsj_env
;
233 jsj_env
= jsj_EnterJava(cx
, &jEnv
);
236 result
= access_java_array_element(cx
, jEnv
, obj
, id
, vp
, JS_TRUE
);
237 jsj_ExitJava(jsj_env
);
242 JavaArray_lookupProperty(JSContext
*cx
, JSObject
*obj
, jsid id
,
243 JSObject
**objp
, JSProperty
**propp
)
246 JSErrorReporter old_reporter
;
247 JSJavaThreadState
*jsj_env
;
249 jsj_env
= jsj_EnterJava(cx
, &jEnv
);
253 old_reporter
= JS_SetErrorReporter(cx
, NULL
);
254 if (access_java_array_element(cx
, jEnv
, obj
, id
, NULL
, JS_FALSE
)) {
256 *propp
= (JSProperty
*)1;
261 JS_SetErrorReporter(cx
, old_reporter
);
262 jsj_ExitJava(jsj_env
);
267 JavaArray_defineProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval value
,
268 JSPropertyOp getter
, JSPropertyOp setter
,
269 uintN attrs
, JSProperty
**propp
)
274 if (attrs
& ~(JSPROP_PERMANENT
|JSPROP_ENUMERATE
))
277 return JavaArray_setPropertyById(cx
, obj
, id
, vp
);
281 JavaArray_getAttributes(JSContext
*cx
, JSObject
*obj
, jsid id
,
282 JSProperty
*prop
, uintN
*attrsp
)
284 /* We don't maintain JS property attributes for Java class members */
285 *attrsp
= JSPROP_PERMANENT
|JSPROP_ENUMERATE
;
290 JavaArray_setAttributes(JSContext
*cx
, JSObject
*obj
, jsid id
,
291 JSProperty
*prop
, uintN
*attrsp
)
293 /* We don't maintain JS property attributes for Java class members */
294 if (*attrsp
!= (JSPROP_PERMANENT
|JSPROP_ENUMERATE
)) {
299 /* Silently ignore all setAttribute attempts */
304 JavaArray_deleteProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
306 JSVersion version
= JS_GetVersion(cx
);
310 if (!JSVERSION_IS_ECMA(version
)) {
311 JS_ReportErrorNumber(cx
, jsj_GetErrorMessage
, NULL
,
312 JSJMSG_JARRAY_PROP_DELETE
);
315 /* Attempts to delete permanent properties are silently ignored
322 JavaArray_defaultValue(JSContext
*cx
, JSObject
*obj
, JSType type
, jsval
*vp
)
324 /* printf("In JavaArray_defaultValue()\n"); */
325 return JavaObject_convert(cx
, obj
, JSTYPE_STRING
, vp
);
329 JavaArray_newEnumerate(JSContext
*cx
, JSObject
*obj
, JSIterateOp enum_op
,
330 jsval
*statep
, jsid
*idp
)
332 JavaObjectWrapper
*java_wrapper
;
333 JSJavaThreadState
*jsj_env
;
335 jsize array_length
, index
;
338 java_wrapper
= JS_GetPrivate(cx
, obj
);
339 /* Check for prototype object */
341 *statep
= JSVAL_NULL
;
343 *idp
= INT_TO_JSVAL(0);
347 /* Get the Java per-thread environment pointer for this JSContext */
348 jsj_env
= jsj_EnterJava(cx
, &jEnv
);
352 array_length
= jsj_GetJavaArrayLength(cx
, jEnv
, java_wrapper
->java_obj
);
353 if (array_length
< 0) {
354 jsj_ExitJava(jsj_env
);
359 case JSENUMERATE_INIT
:
360 *statep
= INT_TO_JSVAL(0);
363 *idp
= INT_TO_JSVAL(array_length
);
366 case JSENUMERATE_NEXT
:
367 index
= JSVAL_TO_INT(*statep
);
368 if (index
< array_length
) {
369 JS_ValueToId(cx
, INT_TO_JSVAL(index
), idp
);
371 *statep
= INT_TO_JSVAL(index
);
375 /* Fall through ... */
377 case JSENUMERATE_DESTROY
:
378 *statep
= JSVAL_NULL
;
387 jsj_ExitJava(jsj_env
);
392 JavaArray_checkAccess(JSContext
*cx
, JSObject
*obj
, jsid id
,
393 JSAccessMode mode
, jsval
*vp
, uintN
*attrsp
)
397 JS_ReportErrorNumber(cx
, jsj_GetErrorMessage
, NULL
,
398 JSJMSG_JARRAY_PROP_WATCH
);
406 JSObjectOps JavaArray_ops
= {
407 /* Mandatory non-null function pointer members. */
408 jsj_wrapper_newObjectMap
, /* newObjectMap */
409 jsj_wrapper_destroyObjectMap
, /* destroyObjectMap */
410 JavaArray_lookupProperty
,
411 JavaArray_defineProperty
,
412 JavaArray_getPropertyById
, /* getProperty */
413 JavaArray_setPropertyById
, /* setProperty */
414 JavaArray_getAttributes
,
415 JavaArray_setAttributes
,
416 JavaArray_deleteProperty
,
417 JavaArray_defaultValue
,
418 JavaArray_newEnumerate
,
419 JavaArray_checkAccess
,
421 /* Optionally non-null members start here. */
422 NULL
, /* thisObject */
423 NULL
, /* dropProperty */
425 NULL
, /* construct */
426 NULL
, /* xdrObject */
427 NULL
, /* hasInstance */
429 NULL
, /* setParent */
432 jsj_wrapper_getRequiredSlot
, /* getRequiredSlot */
433 jsj_wrapper_setRequiredSlot
/* setRequiredSlot */
437 JavaArray_getObjectOps(JSContext
*cx
, JSClass
*clazz
)
439 return &JavaArray_ops
;
442 JSClass JavaArray_class
= {
443 "JavaArray", JSCLASS_HAS_PRIVATE
,
444 NULL
, NULL
, NULL
, NULL
,
445 NULL
, NULL
, JavaObject_convert
, JavaObject_finalize
,
447 /* Optionally non-null members start here. */
448 JavaArray_getObjectOps
,
458 extern JS_IMPORT_DATA(JSObjectOps
) js_ObjectOps
;
461 /* Initialize the JS JavaArray class */
463 jsj_init_JavaArray(JSContext
*cx
, JSObject
*global_obj
)
465 if (!JS_InitClass(cx
, global_obj
,
466 0, &JavaArray_class
, 0, 0,