#include #include #include #include static JavaVM *jvm; #define MAX_OPTIONS 16 static const char *GetMainClassName(void) { static char cString[PATH_MAX]; CFBundleRef mainBundle = CFBundleGetMainBundle(); CFStringRef mainClassName = CFBundleGetValueForInfoDictionaryKey( mainBundle, CFSTR("GSMainClass")); if (!CFStringGetCString( mainClassName, cString, PATH_MAX, kCFStringEncodingUTF8)) { fprintf(stderr, "Can't get main class name\n"); exit(EXIT_FAILURE); } return cString; } static void AppendURLToClassPath(const void *value, void *context) { UInt8 buffer[PATH_MAX]; buffer[0] = ':'; if (!CFURLGetFileSystemRepresentation( value, TRUE, buffer + 1, PATH_MAX - 1)) { fprintf(stderr, "Can't get class path\n"); exit(EXIT_FAILURE); } strcat(context, (const char*)buffer); } #define CLASSPATH_MAX 16384 static char *GetClassPath(void) { static char cString[CLASSPATH_MAX] = "-Djava.class.path"; unsigned length = strlen(cString); CFBundleRef mainBundle = CFBundleGetMainBundle(); CFURLRef resourceURL = CFBundleCopyResourcesDirectoryURL(mainBundle); AppendURLToClassPath(resourceURL, cString); strcat(cString, "/Java"); CFRelease(resourceURL); CFArrayRef jars = CFBundleCopyResourceURLsOfType( mainBundle, CFSTR("jar"), CFSTR("Java")); CFArrayApplyFunction( jars, CFRangeMake(0, CFArrayGetCount(jars)), AppendURLToClassPath, cString); CFRelease(jars); cString[length] = '='; return cString; } static char *GetLibraryPath(void) { static char cString[PATH_MAX + 40] = "-Djava.library.path="; unsigned length = strlen(cString); CFBundleRef mainBundle = CFBundleGetMainBundle(); CFURLRef url = CFBundleCopyBundleURL(mainBundle); if (!CFURLGetFileSystemRepresentation( url, TRUE, (UInt8 *)(cString + length), PATH_MAX)) { fprintf(stderr, "Can't get library path\n"); exit(EXIT_FAILURE); } CFRelease(url); strcat(cString, "/Contents/Libraries"); return cString; } static JNIEnv *CreateJavaVM(void) { JNIEnv *env; jint result; unsigned noptions = 0; JavaVMOption options[MAX_OPTIONS]; options[noptions++].optionString = GetClassPath(); options[noptions++].optionString = GetLibraryPath(); JavaVMInitArgs vm_args; vm_args.version = JNI_VERSION_1_2; vm_args.options = options; vm_args.nOptions = noptions; vm_args.ignoreUnrecognized = JNI_TRUE; // TODO check for existence of 1.5, and fail gracefully if it doesn't // exist setenv("JAVA_JVM_VERSION", "1.5", 1); result = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args); if (result < 0) { fprintf(stderr, "Can't create Java VM\n"); exit(EXIT_FAILURE); } return env; } static void Die(JNIEnv *env) { if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionDescribe(env); } else { fprintf(stderr, "Unknown problem; exiting\n"); } (*jvm)->DestroyJavaVM(jvm); exit(EXIT_FAILURE); } static jclass GetMainClass(JNIEnv *env) { // TODO load main class from Info.plist jclass mainClass = (*env)->FindClass( env, GetMainClassName()); if (mainClass == NULL) { Die(env); } return mainClass; } static jmethodID GetMainMethod(JNIEnv *env, jclass mainClass) { jmethodID mainMethod = (*env)->GetStaticMethodID( env, mainClass, "main", "([Ljava/lang/String;)V"); if (mainMethod == NULL) { Die(env); } return mainMethod; } static void CallMain(JNIEnv *env, jclass mainClass, jmethodID mainMethod) { jobject args = (*env)->NewObjectArray(env, 0, mainClass, NULL); if (args == NULL) { Die(env); } (*env)->CallStaticVoidMethod(env, mainClass, mainMethod, args); if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionDescribe(env); exit(EXIT_FAILURE); } } static void RunMain(JNIEnv *env) { jclass mainClass = GetMainClass(env); jmethodID mainMethod = GetMainMethod(env, mainClass); CallMain(env, mainClass, mainMethod); } int main(int argc, const char *argv[]) { JNIEnv *env = CreateJavaVM(); RunMain(env); return EXIT_SUCCESS; }