1 /* -*- Mode: C; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the Mozilla Public License Version 2.0.
7 // See license.mkd for licensing and copyright information.
8 // -------------------------------------------------------------------------*/
13 #include "squirreljme.h"
14 #include "sjme/debug.h"
16 sjme_jboolean
sjme_jni_checkVMException(JNIEnv
* env
)
18 /* Was there an exception? */
19 if ((*env
)->ExceptionCheck(env
))
22 (*env
)->ExceptionDescribe(env
);
28 return SJME_JNI_FALSE
;
31 jintArray
sjme_jni_mappedArrayInt(JNIEnv
* env
,
32 jint
* buf
, jint off
, jint len
)
35 /* We need this to get raw arrays. */
36 byteBufferClassy
= (*env
)->FindClass(env
, "java/nio/ByteBuffer");
37 if (byteBufferClassy
== NULL
)
38 sjme_die("No ByteBuffer?");
40 /* Create a byte buffer around the buffer. */
41 byteBuffer
= (*env
)->NewDirectByteBuffer(env
,
42 (void*)(((sjme_intPointer
)buf
) + ((sjme_intPointer
)bufOff
)), bufLen
);
43 if (byteBuffer
== NULL
)
44 return SJME_ERROR_CANNOT_CREATE
;
51 void sjme_jni_throwMLECallError(JNIEnv
* env
, sjme_errorCode code
)
53 sjme_jni_throwThrowable(env
, code
,
54 "cc/squirreljme/jvm/mle/exceptions/MLECallError");
57 void sjme_jni_throwThrowable(JNIEnv
* env
, sjme_errorCode code
,
64 /* Get the class where the exception is. */
65 tossingClass
= (*env
)->FindClass(env
, type
);
66 if (tossingClass
== NULL
)
68 sjme_die("Could not find exception class?");
72 /* Generate a message accordingly. */
73 memset(buf
, 0, sizeof(buf
));
74 snprintf(buf
, BUF_SIZE
- 1, "Native error: %d",
75 (int)sjme_error_default(code
));
76 buf
[BUF_SIZE
- 1] = 0;
79 if ((*env
)->ThrowNew(env
, tossingClass
, buf
) != 0)
80 sjme_die("Could not throw a new throwable?");
84 void sjme_jni_throwVMException(JNIEnv
* env
, sjme_errorCode code
)
86 sjme_jni_throwThrowable(env
, code
,
87 "cc/squirreljme/emulator/vm/VMException");
90 void* sjme_jni_recoverPointer(JNIEnv
* env
, sjme_lpcstr className
,
95 jmethodID pointerMethod
;
102 if (env
== NULL
|| className
== NULL
)
104 sjme_jni_throwMLECallError(env
, SJME_ERROR_NULL_ARGUMENTS
);
109 classy
= (*env
)->FindClass(env
, className
);
110 baseClassy
= (*env
)->FindClass(env
, DESC_DYLIB_HAS_OBJECT_POINTER
);
111 if (classy
== NULL
|| baseClassy
== NULL
)
113 sjme_jni_throwMLECallError(env
, SJME_ERROR_INVALID_CLASS_NAME
);
117 /* Incorrect type. */
118 if (!(*env
)->IsInstanceOf(env
, instance
, classy
) ||
119 !(*env
)->IsInstanceOf(env
, instance
, baseClassy
))
121 sjme_jni_throwMLECallError(env
, SJME_ERROR_CLASS_CAST
);
125 /* Get pointer object method. */
126 pointerMethod
= (*env
)->GetMethodID(env
, baseClassy
,
127 "objectPointer", "()J");
128 if (pointerMethod
== NULL
)
129 sjme_die("No objectPointer() in instance?");
131 /* Cast pencil data. */
132 return (void*)((intptr_t)((*env
)->CallLongMethod(
133 env
, instance
, pointerMethod
)));
136 sjme_scritchui_pencil
sjme_jni_recoverPencil(JNIEnv
* env
, jobject g
)
142 return (sjme_scritchui_pencil
)sjme_jni_recoverPointer(env
,
143 DESC_DYLIB_PENCIL
, g
);
146 sjme_scritchui_pencilFont
sjme_jni_recoverFont(JNIEnv
* env
,
147 jobject fontInstance
)
150 if (fontInstance
== NULL
)
153 return (sjme_scritchui_pencilFont
)sjme_jni_recoverPointer(env
,
154 DESC_DYLIB_PENCILFONT
, fontInstance
);
157 sjme_errorCode
sjme_jni_fillFrontEnd(JNIEnv
* env
, sjme_frontEnd
* into
,
162 if (env
== NULL
|| into
== NULL
)
163 return SJME_ERROR_NULL_ARGUMENTS
;
165 /* Store referenced VM. */
167 (*env
)->GetJavaVM(env
, &vm
);
170 /* Need to reference an object? */
172 into
->wrapper
= (*env
)->NewGlobalRef(env
, ref
);
174 into
->wrapper
= NULL
;
176 return SJME_ERROR_NONE
;
179 sjme_errorCode
sjme_jni_recoverEnv(
180 sjme_attrInOutNotNull JNIEnv
** outEnv
,
181 sjme_attrInNotNull JavaVM
* inVm
)
186 if (outEnv
== NULL
|| inVm
== NULL
)
187 return SJME_ERROR_NULL_ARGUMENTS
;
189 /* Try to get the environment for the current thread. */
191 jniError
= (*inVm
)->GetEnv(inVm
, (void**)&env
, JNI_VERSION_1_1
);
192 if (jniError
!= JNI_OK
|| env
== NULL
)
193 return SJME_ERROR_NO_JAVA_ENVIRONMENT
;
197 return SJME_ERROR_NONE
;
200 sjme_errorCode
sjme_jni_recoverEnvFrontEnd(
201 sjme_attrInOutNotNull JNIEnv
** outEnv
,
202 sjme_attrInNotNull
const sjme_frontEnd
* inFrontEnd
)
204 if (outEnv
== NULL
|| inFrontEnd
== NULL
)
205 return SJME_ERROR_NULL_ARGUMENTS
;
208 return sjme_jni_recoverEnv(outEnv
, inFrontEnd
->data
);
211 static sjme_errorCode
sjme_jni_jstringCharAt(
212 sjme_attrInNotNull
const sjme_charSeq
* inSeq
,
213 sjme_attrInPositive sjme_jint inIndex
,
214 sjme_attrOutNotNull sjme_jchar
* outChar
)
216 sjme_errorCode error
;
219 const jchar
* stringChars
;
223 if (inSeq
== NULL
|| outChar
== NULL
)
224 return SJME_ERROR_NULL_ARGUMENTS
;
228 if (sjme_error_is(error
= sjme_jni_recoverEnvFrontEnd(
229 &env
, &inSeq
->frontEnd
)) || env
== NULL
)
230 return sjme_error_default(error
);
233 string
= inSeq
->frontEnd
.wrapper
;
235 /* Not within the string bounds? */
236 len
= (*env
)->GetStringLength(env
, string
);
237 if (inIndex
< 0 || inIndex
>= len
)
238 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
240 /* Need to access characters just to read one, sadly. */
242 stringChars
= (*env
)->GetStringChars(env
, string
, &isCopy
);
244 /* Copy character. */
245 *outChar
= stringChars
[inIndex
];
248 (*env
)->ReleaseStringChars(env
, string
, stringChars
);
251 return SJME_ERROR_NONE
;
254 static sjme_errorCode
sjme_jni_jstringDelete(
255 sjme_attrInNotNull sjme_charSeq
* inSeq
)
257 sjme_errorCode error
;
262 return SJME_ERROR_NULL_ARGUMENTS
;
266 if (sjme_error_is(error
= sjme_jni_recoverEnvFrontEnd(
267 &env
, &inSeq
->frontEnd
)) || env
== NULL
)
268 return sjme_error_default(error
);
271 string
= inSeq
->frontEnd
.wrapper
;
273 /* Remove global reference. */
274 (*env
)->DeleteGlobalRef(env
, string
);
275 inSeq
->frontEnd
.wrapper
= NULL
;
278 return SJME_ERROR_NONE
;
281 static sjme_errorCode
sjme_jni_jstringLength(
282 sjme_attrInNotNull
const sjme_charSeq
* inSeq
,
283 sjme_attrOutNotNull sjme_jint
* outLen
)
285 sjme_errorCode error
;
289 if (inSeq
== NULL
|| outLen
== NULL
)
290 return SJME_ERROR_NULL_ARGUMENTS
;
294 if (sjme_error_is(error
= sjme_jni_recoverEnvFrontEnd(
295 &env
, &inSeq
->frontEnd
)) || env
== NULL
)
296 return sjme_error_default(error
);
299 string
= inSeq
->frontEnd
.wrapper
;
301 /* Get string length. */
302 *outLen
= (*env
)->GetStringLength(env
, string
);
305 return SJME_ERROR_NONE
;
308 static const sjme_charSeq_functions sjme_jni_jstringFunctions
=
310 .charAt
= sjme_jni_jstringCharAt
,
311 .delete = sjme_jni_jstringDelete
,
312 .length
= sjme_jni_jstringLength
,
315 sjme_errorCode
sjme_jni_jstringCharSeqStatic(
316 sjme_attrInNotNull JNIEnv
* env
,
317 sjme_attrInNotNull sjme_charSeq
* inOutSeq
,
318 sjme_attrInNotNull jstring inString
)
320 sjme_frontEnd frontEnd
;
321 sjme_errorCode error
;
323 if (env
== NULL
|| inOutSeq
== NULL
|| inString
== NULL
)
324 return SJME_ERROR_NULL_ARGUMENTS
;
326 /* Setup front end. */
327 memset(&frontEnd
, 0, sizeof(frontEnd
));
328 if (sjme_error_is(error
= sjme_jni_fillFrontEnd(env
,
329 &frontEnd
, inString
)))
330 return sjme_error_default(error
);
332 /* Initialize via forward. */
333 return sjme_charSeq_newStatic(
334 inOutSeq
, &sjme_jni_jstringFunctions
,
339 jlong
sjme_jni_jlong(sjme_jlong value
)
344 sjme_errorCode
sjme_jni_pushWeakLink(
345 sjme_attrInNotNull JNIEnv
* env
,
346 sjme_attrInNotNull jobject javaObject
,
347 sjme_attrInNotNull sjme_alloc_weak nativeWeak
)
349 jclass collectorClass
;
350 jmethodID pushMethod
;
352 if (env
== NULL
|| javaObject
== NULL
|| nativeWeak
== NULL
)
353 return SJME_ERROR_NULL_ARGUMENTS
;
355 /* Find collector class. */
356 collectorClass
= (*env
)->FindClass(env
, DESC_DYLIB_COLLECTOR
);
357 if (collectorClass
== NULL
)
358 return SJME_ERROR_JNI_EXCEPTION
;
360 /* Find push method. */
361 pushMethod
= (*env
)->GetStaticMethodID(env
, collectorClass
,
362 "__push", "(Ljava/lang/Object;J)V");
363 if (pushMethod
== NULL
)
364 return SJME_ERROR_JNI_EXCEPTION
;
367 (*env
)->CallStaticVoidMethod(env
, collectorClass
, pushMethod
,
368 javaObject
, (jlong
)nativeWeak
);
370 /* Check for failure. */
371 if (sjme_jni_checkVMException(env
))
372 return SJME_ERROR_JNI_EXCEPTION
;
375 return SJME_ERROR_NONE
;
378 sjme_errorCode
sjme_jni_arrayType(
379 sjme_attrInNotNull JNIEnv
* env
,
380 sjme_attrInNotNull jobject array
,
381 sjme_attrOutNotNull sjme_basicTypeId
* outType
)
385 if (env
== NULL
|| array
== NULL
|| outType
== NULL
)
386 return SJME_ERROR_NULL_ARGUMENTS
;
388 if ((*env
)->IsInstanceOf(env
, array
, (*env
)->FindClass(env
, "[Z")))
389 *outType
= SJME_BASIC_TYPE_ID_BOOLEAN
;
390 else if ((*env
)->IsInstanceOf(env
, array
, (*env
)->FindClass(env
, "[B")))
391 *outType
= SJME_BASIC_TYPE_ID_BYTE
;
392 else if ((*env
)->IsInstanceOf(env
, array
, (*env
)->FindClass(env
, "[S")))
393 *outType
= SJME_BASIC_TYPE_ID_SHORT
;
394 else if ((*env
)->IsInstanceOf(env
, array
, (*env
)->FindClass(env
, "[C")))
395 *outType
= SJME_BASIC_TYPE_ID_CHARACTER
;
396 else if ((*env
)->IsInstanceOf(env
, array
, (*env
)->FindClass(env
, "[I")))
397 *outType
= SJME_BASIC_TYPE_ID_INTEGER
;
398 else if ((*env
)->IsInstanceOf(env
, array
, (*env
)->FindClass(env
, "[J")))
399 *outType
= SJME_BASIC_TYPE_ID_LONG
;
400 else if ((*env
)->IsInstanceOf(env
, array
, (*env
)->FindClass(env
, "[F")))
401 *outType
= SJME_BASIC_TYPE_ID_FLOAT
;
402 else if ((*env
)->IsInstanceOf(env
, array
, (*env
)->FindClass(env
, "[D")))
403 *outType
= SJME_BASIC_TYPE_ID_DOUBLE
;
405 return SJME_ERROR_INVALID_ARGUMENT
;
408 return SJME_ERROR_NONE
;
411 sjme_errorCode
sjme_jni_arrayGetElements(
412 sjme_attrInNotNull JNIEnv
* env
,
413 sjme_attrInNotNull jobject array
,
414 sjme_attrOutNotNull sjme_pointer
* rawBuf
,
415 sjme_attrOutNotNull jboolean
* isCopy
,
416 sjme_attrOutNullable sjme_jint
* typeSize
)
418 sjme_errorCode error
;
419 sjme_javaTypeId type
;
421 if (env
== NULL
|| array
== NULL
|| rawBuf
== NULL
|| isCopy
== NULL
)
422 return SJME_ERROR_NULL_ARGUMENTS
;
424 /* Get array type. */
426 if (sjme_error_is(error
= sjme_jni_arrayType(env
, array
,
428 return sjme_error_default(error
);
430 /* Depends on the type. */
433 case SJME_BASIC_TYPE_ID_BOOLEAN
:
434 *rawBuf
= (*env
)->GetBooleanArrayElements(env
, array
, isCopy
);
435 if (typeSize
!= NULL
)
439 case SJME_BASIC_TYPE_ID_BYTE
:
440 *rawBuf
= (*env
)->GetByteArrayElements(env
, array
, isCopy
);
441 if (typeSize
!= NULL
)
445 case SJME_BASIC_TYPE_ID_SHORT
:
446 *rawBuf
= (*env
)->GetShortArrayElements(env
, array
, isCopy
);
447 if (typeSize
!= NULL
)
451 case SJME_BASIC_TYPE_ID_CHARACTER
:
452 *rawBuf
= (*env
)->GetCharArrayElements(env
, array
, isCopy
);
453 if (typeSize
!= NULL
)
457 case SJME_BASIC_TYPE_ID_INTEGER
:
458 *rawBuf
= (*env
)->GetIntArrayElements(env
, array
, isCopy
);
459 if (typeSize
!= NULL
)
463 case SJME_BASIC_TYPE_ID_LONG
:
464 *rawBuf
= (*env
)->GetLongArrayElements(env
, array
, isCopy
);
465 if (typeSize
!= NULL
)
469 case SJME_BASIC_TYPE_ID_FLOAT
:
470 *rawBuf
= (*env
)->GetFloatArrayElements(env
, array
, isCopy
);
471 if (typeSize
!= NULL
)
475 case SJME_BASIC_TYPE_ID_DOUBLE
:
476 *rawBuf
= (*env
)->GetDoubleArrayElements(env
, array
, isCopy
);
477 if (typeSize
!= NULL
)
482 return SJME_ERROR_INVALID_ARGUMENT
;
486 return SJME_ERROR_NONE
;
489 sjme_errorCode
sjme_jni_arrayReleaseElements(
490 sjme_attrInNotNull JNIEnv
* env
,
491 sjme_attrInNotNull jarray array
,
492 sjme_attrInNotNull sjme_pointer rawBuf
)
494 sjme_errorCode error
;
495 sjme_javaTypeId type
;
497 if (env
== NULL
|| array
== NULL
|| rawBuf
== NULL
)
498 return SJME_ERROR_NULL_ARGUMENTS
;
500 /* Get array type. */
502 if (sjme_error_is(error
= sjme_jni_arrayType(env
, array
,
504 return sjme_error_default(error
);
506 /* Depends on the type. */
509 case SJME_BASIC_TYPE_ID_BOOLEAN
:
510 (*env
)->ReleaseBooleanArrayElements(env
, array
, rawBuf
, 0);
513 case SJME_BASIC_TYPE_ID_BYTE
:
514 (*env
)->ReleaseByteArrayElements(env
, array
, rawBuf
, 0);
517 case SJME_BASIC_TYPE_ID_SHORT
:
518 (*env
)->ReleaseShortArrayElements(env
, array
, rawBuf
, 0);
521 case SJME_BASIC_TYPE_ID_CHARACTER
:
522 (*env
)->ReleaseCharArrayElements(env
, array
, rawBuf
, 0);
525 case SJME_BASIC_TYPE_ID_INTEGER
:
526 (*env
)->ReleaseIntArrayElements(env
, array
, rawBuf
, 0);
529 case SJME_BASIC_TYPE_ID_LONG
:
530 (*env
)->ReleaseLongArrayElements(env
, array
, rawBuf
, 0);
533 case SJME_BASIC_TYPE_ID_FLOAT
:
534 (*env
)->ReleaseFloatArrayElements(env
, array
, rawBuf
, 0);
537 case SJME_BASIC_TYPE_ID_DOUBLE
:
538 (*env
)->ReleaseDoubleArrayElements(env
, array
, rawBuf
, 0);
542 return SJME_ERROR_INVALID_ARGUMENT
;
546 return SJME_ERROR_NONE
;