lwjgl/src/native/common/common_tools.c

403 lines
13 KiB
C

/*
* Copyright (c) 2002-2008 LWJGL Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'LWJGL' nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* $Id$
*
* @author elias_naur <elias_naur@users.sourceforge.net>
* @version $Revision$
*/
#include <jni.h>
#include <stdlib.h>
#include "common_tools.h"
#include "org_lwjgl_DefaultSysImplementation.h"
static bool debug = false;
static JavaVM *jvm;
static jmethodID mByteBuffer_asReadOnlyBuffer;
static jmethodID mPointerWrapper_getPointer;
void initAttribList(attrib_list_t *list) {
list->current_index = 0;
}
void putAttrib(attrib_list_t *list, int attrib) {
if (list->current_index == ATTRIB_LIST_SIZE) {
printfDebug("Ignoring attrib %d: attrib list size too small", attrib);
return;
}
list->attribs[list->current_index] = attrib;
list->current_index++;
}
JNIEXPORT jint JNICALL Java_org_lwjgl_DefaultSysImplementation_getPointerSize(JNIEnv *env, jclass clazz) {
return (jint)sizeof(void *);
}
JNIEXPORT void JNICALL Java_org_lwjgl_DefaultSysImplementation_setDebug
(JNIEnv *env, jobject ignored, jboolean enable) {
debug = enable == JNI_TRUE ? true : false;
}
bool isDebugEnabled(void) {
return debug;
}
static int do_vsnprintf(char* buffer, size_t buffer_size, const char *format, va_list ap) {
#ifdef _MSC_VER
return vsnprintf_s(buffer, buffer_size, _TRUNCATE, format, ap);
#else
va_list cp_ap;
va_copy(cp_ap, ap);
int res = vsnprintf(buffer, buffer_size, format, cp_ap);
va_end(cp_ap);
return res;
#endif
}
static jstring sprintfJavaString(JNIEnv *env, const char *format, va_list ap) {
int buffer_size = 2048;
char *buffer;
jstring str;
int str_size;
buffer = (char *)malloc(sizeof(char)*buffer_size);
if (buffer == NULL)
return NULL;
str_size = do_vsnprintf(buffer, buffer_size, format, ap);
if (str_size > buffer_size) {
free(buffer);
buffer_size = str_size + 1;
buffer = (char *)malloc(sizeof(char)*buffer_size);
if (buffer == NULL)
return NULL;
do_vsnprintf(buffer, buffer_size, format, ap);
}
str = (*env)->NewStringUTF(env, buffer);
free(buffer);
return str;
}
void printfDebugJava(JNIEnv *env, const char *format, ...) {
jstring str;
jclass org_lwjgl_LWJGLUtil_class;
jmethodID log_method;
va_list ap;
if (isDebugEnabled() && !(*env)->ExceptionOccurred(env)) {
va_start(ap, format);
str = sprintfJavaString(env, format, ap);
va_end(ap);
org_lwjgl_LWJGLUtil_class = (*env)->FindClass(env, "org/lwjgl/LWJGLUtil");
if (org_lwjgl_LWJGLUtil_class == NULL)
return;
log_method = (*env)->GetStaticMethodID(env, org_lwjgl_LWJGLUtil_class, "log", "(Ljava/lang/CharSequence;)V");
if (log_method == NULL)
return;
(*env)->CallStaticVoidMethod(env, org_lwjgl_LWJGLUtil_class, log_method, str);
}
}
void printfDebug(const char *format, ...) {
va_list ap;
va_start(ap, format);
if (isDebugEnabled())
vfprintf(stderr, format, ap);
va_end(ap);
}
static void throwFormattedGeneralException(JNIEnv * env, const char *exception_name, const char *format, va_list ap) {
jclass cls;
jstring str;
jmethodID exception_constructor;
jobject exception;
if ((*env)->ExceptionCheck(env) == JNI_TRUE)
return; // The JVM crashes if we try to throw two exceptions from one native call
str = sprintfJavaString(env, format, ap);
cls = (*env)->FindClass(env, exception_name);
exception_constructor = (*env)->GetMethodID(env, cls, "<init>", "(Ljava/lang/String;)V");
exception = (*env)->NewObject(env, cls, exception_constructor, str);
(*env)->Throw(env, exception);
}
void throwGeneralException(JNIEnv * env, const char *exception_name, const char * err) {
jclass cls;
if ((*env)->ExceptionCheck(env) == JNI_TRUE)
return; // The JVM crashes if we try to throw two exceptions from one native call
cls = (*env)->FindClass(env, exception_name);
(*env)->ThrowNew(env, cls, err);
}
void throwFMODException(JNIEnv * env, const char * err) {
throwGeneralException(env, "org/lwjgl/fmod3/FMODException", err);
}
void throwFormattedRuntimeException(JNIEnv * env, const char *format, ...) {
va_list ap;
va_start(ap, format);
throwFormattedGeneralException(env, "java/lang/RuntimeException", format, ap);
va_end(ap);
}
void throwFormattedException(JNIEnv * env, const char *format, ...) {
va_list ap;
va_start(ap, format);
throwFormattedGeneralException(env, "org/lwjgl/LWJGLException", format, ap);
va_end(ap);
}
void throwException(JNIEnv * env, const char * err) {
throwGeneralException(env, "org/lwjgl/LWJGLException", err);
}
// retrieves the locale-specific C string
char * GetStringNativeChars(JNIEnv *env, jstring jstr) {
jbyteArray bytes = 0;
jthrowable exc;
char *result = 0;
jclass jcls_str;
jmethodID MID_String_getBytes;
/* out of memory error? */
if ((*env)->EnsureLocalCapacity(env, 2) < 0) {
return 0;
}
// aquire getBytes method
jcls_str = (*env)->FindClass(env, "java/lang/String");
MID_String_getBytes = (*env)->GetMethodID(env, jcls_str, "getBytes", "()[B");
// get the bytes
bytes = (jbyteArray) (*env)->CallObjectMethod(env, jstr, MID_String_getBytes);
exc = (*env)->ExceptionOccurred(env);
// if no exception occured while getting bytes - continue
if (!exc) {
jint len = (*env)->GetArrayLength(env, bytes);
result = (char *) malloc(len + 1);
if (result == 0) {
throwGeneralException(env, "java/lang/OutOfMemoryError", NULL);
(*env)->DeleteLocalRef(env, bytes);
return 0;
}
(*env)->GetByteArrayRegion(env, bytes, 0, len, (jbyte *) result);
result[len] = 0; /* NULL-terminate */
} else {
(*env)->DeleteLocalRef(env, exc);
}
(*env)->DeleteLocalRef(env, bytes);
return (char*) result;
}
/* creates locale specific string, unsigned argument to
* match GLuchar and ALuchar types
*/
jstring NewStringNativeUnsigned(JNIEnv *env, const unsigned char *ustr) {
const char *str = (const char *)ustr;
if (str == NULL)
return NULL;
return NewStringNativeWithLength(env, str, (jsize)strlen(str));
}
// creates locale specific string
jstring NewStringNativeWithLength(JNIEnv *env, const char *str, jsize length) {
jclass jcls_str;
jmethodID jmethod_str;
jstring result;
jbyteArray bytes;
if (str==NULL) {
return NULL;
}
jcls_str = (*env)->FindClass(env,"java/lang/String");
if (jcls_str == NULL)
return NULL;
jmethod_str = (*env)->GetMethodID(env,jcls_str, "<init>", "([B)V");
if (jmethod_str == NULL)
return NULL;
bytes = 0;
if ((*env)->EnsureLocalCapacity(env,2) < 0) {
return NULL; /* out of memory error */
}
bytes = (*env)->NewByteArray(env,length);
if (bytes != NULL) {
(*env)->SetByteArrayRegion(env,bytes, 0, length, (jbyte *)str);
result = (jstring)(*env)->NewObject(env,jcls_str, jmethod_str, bytes);
(*env)->DeleteLocalRef(env,bytes);
return result;
} /* else fall through */
return NULL;
}
bool ext_InitializeFunctions(ExtGetProcAddressPROC gpa, int num_functions, ExtFunction *functions) {
int i;
void **ext_function_pointer_pointer;
for (i = 0; i < num_functions; i++) {
ExtFunction *function = functions + i;
if (function->ext_function_name != NULL) {
void *ext_func_pointer = gpa(function->ext_function_name);
if (ext_func_pointer == NULL) {
printfDebug("Could not locate symbol %s\n", function->ext_function_name);
return false;
}
ext_function_pointer_pointer = function->ext_function_pointer;
*ext_function_pointer_pointer = ext_func_pointer;
}
}
return true;
}
jobject NewReadOnlyDirectByteBuffer(JNIEnv* env, const void* address, jlong capacity) {
jobject buffer = (*env)->NewDirectByteBuffer(env, (void *)address, capacity);
return (*env)->CallObjectMethod(env, buffer, mByteBuffer_asReadOnlyBuffer);
}
jobject newJavaManagedByteBuffer(JNIEnv *env, const int size) {
jclass bufferutils_class = (*env)->FindClass(env, "org/lwjgl/BufferUtils");
jmethodID createByteBuffer = (*env)->GetStaticMethodID(env, bufferutils_class, "createByteBuffer", "(I)Ljava/nio/ByteBuffer;");
jobject buffer = (*env)->CallStaticObjectMethod(env, bufferutils_class, createByteBuffer, size);
return buffer;
}
void ext_InitializeClass(JNIEnv *env, jclass clazz, ExtGetProcAddressPROC gpa, int num_functions, JavaMethodAndExtFunction *functions) {
JNINativeMethod *methods;
JavaMethodAndExtFunction *function;
void *ext_func_pointer;
void **ext_function_pointer_pointer;
JNINativeMethod *method;
int i, num_natives = 0;
if (clazz == NULL) {
throwException(env, "Null class");
return;
}
methods = (JNINativeMethod *)malloc(num_functions*sizeof(JNINativeMethod));
for (i = 0; i < num_functions; i++) {
function = functions + i;
if (function->ext_function_name != NULL) {
ext_func_pointer = gpa(function->ext_function_name);
if (ext_func_pointer == NULL) {
printfDebug("Could not locate symbol %s\n", function->ext_function_name);
if ( function->optional )
continue;
free(methods);
throwException(env, "Missing driver symbols");
return;
}
ext_function_pointer_pointer = function->ext_function_pointer;
*ext_function_pointer_pointer = ext_func_pointer;
}
method = methods + num_natives;
method->name = function->method_name;
method->signature = function->signature;
method->fnPtr = function->method_pointer;
num_natives++;
}
(*env)->RegisterNatives(env, clazz, methods, num_natives);
free(methods);
}
bool getBooleanProperty(JNIEnv *env, const char* propertyName) {
jstring property = NewStringNativeWithLength(env, propertyName, (jsize)strlen(propertyName));
jclass org_lwjgl_LWJGLUtil_class;
jmethodID getBoolean;
if (property == NULL)
return false;
org_lwjgl_LWJGLUtil_class = (*env)->FindClass(env, "org/lwjgl/LWJGLUtil");
if (org_lwjgl_LWJGLUtil_class == NULL)
return false;
getBoolean = (*env)->GetStaticMethodID(env, org_lwjgl_LWJGLUtil_class, "getPrivilegedBoolean", "(Ljava/lang/String;)Z");
if (getBoolean == NULL)
return false;
return (*env)->CallStaticBooleanMethod(env, org_lwjgl_LWJGLUtil_class, getBoolean, property) ? true : false;
}
jlong getPointerWrapperAddress(JNIEnv *env, jobject wrapper) {
return (*env)->CallLongMethod(env, wrapper, mPointerWrapper_getPointer);
}
JNIEnv *getThreadEnv() {
JNIEnv *env;
(*jvm)->GetEnv(jvm, (void *)&env, JNI_VERSION_1_4);
return env;
}
JNIEnv *attachCurrentThread() {
JNIEnv *env;
(*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
return env;
}
void detachCurrentThread() {
(*jvm)->DetachCurrentThread(jvm);
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env;
jclass clazz;
jvm = vm;
env = getThreadEnv();
clazz = (*env)->FindClass(env, "java/nio/ByteBuffer");
mByteBuffer_asReadOnlyBuffer = (*env)->GetMethodID(env, clazz, "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
clazz = (*env)->FindClass(env, "org/lwjgl/PointerWrapper");
mPointerWrapper_getPointer = (*env)->GetMethodID(env, clazz, "getPointer", "()J");
return JNI_VERSION_1_4;
}
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) {
}
bool positionBuffer(JNIEnv *env, jobject buffer, jint position) {
jclass buffer_class;
jmethodID position_method;
buffer_class = (*env)->GetObjectClass(env, buffer);
if (buffer_class == NULL)
return false;
position_method = (*env)->GetMethodID(env, buffer_class, "position", "(I)Ljava/nio/Buffer;");
if (position_method == NULL)
return false;
(*env)->CallObjectMethod(env, buffer, position_method, position);
return true;
}