/*---------------------------------------------------------------------------- ChucK Concurrent, On-the-fly Audio Programming Language Compiler and Virtual Machine Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved. http://chuck.stanford.edu/ http://chuck.cs.princeton.edu/ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 U.S.A. -----------------------------------------------------------------------------*/ //-----------------------------------------------------------------------------// name: util_platforms.cpp// desc: platform-specific utilities, e.g., for Android and various//// author: Andriy Kunitsyn (kunitzin@gmail.com) | original ChuckAndroid// Ge Wang (https://ccrma.stanford.edu/~ge/)// date: Summer 2021//-----------------------------------------------------------------------------#include "util_platforms.h"#include "util_string.h"#include "chuck_errmsg.h" #ifdef __PLATFORM_WIN32__#ifndef __CHUNREAL_ENGINE__#include <windows.h> // for win32_tmpfile()#else // 1.5.0.0 (ge) | #chunreal // unreal engine on windows disallows including windows.h#include "Windows/MinWindows.h"#endif // #ifndef __CHUNREAL_ENGINE__#endif // #ifdef __PLATFORM_WIN32__ #include <sys/stat.h> //-----------------------------------------------------------------------------// name: ck_openFileAutoExt()// desc: open a file by name, first as is, and if needed concatenateing ".ck"// this potentially modifies the contents of fname//-----------------------------------------------------------------------------FILE * ck_openFileAutoExt( std::string & filenameMutable, const std::string & extension ){#ifdef __ANDROID__ if( strncmp(filenameMutable.c_str(), "jar:", strlen("jar:")) == 0 ) { int fd = 0; if( !ChuckAndroid::copyJARURLFileToTemporary(filenameMutable.c_str(), &fd) ) { EM_error2( 0, "unable to download from JAR URL: %s", filenameMutable.c_str() ); return NULL; } return fdopen(fd, "rb"); }#endif // __ANDROID__ // try opening FILE * fd = fopen( filenameMutable.c_str(), "rb" ); // file open? if( !fd ) { // check if filename has extension, ignoring case if( !extension_matches( filenameMutable, extension, TRUE ) ) { // concat std::string tryThis = filenameMutable + extension; // try opening again fd = fopen( tryThis.c_str(), "rb" ); // if successful update filename filenameMutable = tryThis; } } return fd;} //-----------------------------------------------------------------------------// name: win32_tmpfile()// desc: replacement for broken tmpfile() on Windows Vista + 7//-----------------------------------------------------------------------------#ifdef __PLATFORM_WIN32__FILE * win32_tmpfile(){ char tmp_path[MAX_PATH]; char file_path[MAX_PATH]; FILE * file = NULL; #ifndef __CHUNREAL_ENGINE__ if( GetTempPath(256, tmp_path) == 0 )#else // 1.5.0.0 (ge) | #chunreal explicit call ASCII version if( GetTempPathA(256, tmp_path) == 0 )#endif return NULL; #ifndef __CHUNREAL_ENGINE__ if( GetTempFileName(tmp_path, "mA", 0, file_path) == 0 )#else // 1.5.0.0 (ge) | #chunreal explicit call ASCII version if( GetTempFileNameA(tmp_path, "mA", 0, file_path) == 0 )#endif return NULL; file = fopen( file_path, "wb+D" ); return file;}#endif // #ifdef __PLATFORM_WIN32__ //-----------------------------------------------------------------------------// name: android_tmpfile()// desc: replacement for broken tmpfile() on Android//-----------------------------------------------------------------------------#ifdef __ANDROID__FILE * android_tmpfile(){ return ChuckAndroid::getTemporaryFile();}#endif //-----------------------------------------------------------------------------// name: android_tmpfile()// desc: replacement for broken tmpfile() on Android//-----------------------------------------------------------------------------FILE * ck_tmpfile(){ FILE * fd = NULL;#ifdef __PLATFORM_WIN32__ fd = win32_tmpfile();#elif defined (__ANDROID__) fd = android_tmpfile();#else fd = tmpfile();#endif return fd;} //-----------------------------------------------------------------------------// name: ck_isdir()// desc: check if file is a directory//-----------------------------------------------------------------------------t_CKBOOL ck_isdir( const std::string & path ){ // shuttle struct stat fs; // stat the path and check flag (is path not there, also returns false) return (stat( path.c_str(), &fs )==0 && fs.st_mode & S_IFDIR);} //-----------------------------------------------------------------------------#ifdef __ANDROID__//-----------------------------------------------------------------------------#include <jni.h>#include <fcntl.h>#include <unistd.h>#include <string> static JavaVM * jvm_instance = NULL; JNIEXPORT jint JNICALL JNI_OnLoad( JavaVM * vm, void * reserved ){ jvm_instance = vm; return JNI_VERSION_1_6;} JavaVM * ChuckAndroid::getJVM(){ return jvm_instance;} //-----------------------------------------------------------------------------// name: class JNIEnvWrapper// desc: Wrapper around JNIEnv. Serves three purposes:// - releases JNIEnv and Java objects in RAII fashion// - removes the need to get method IDs// - throws JNIEnvWrapperException exception on Java exceptions//-----------------------------------------------------------------------------class JNIEnvWrapper{public: JNIEnvWrapper(JavaVM * jvm); ~JNIEnvWrapper(); bool IsValid() const; jclass FindClass(const char * class_signature); jobject ConstructNewObject(jclass constructed_class, const char * constructor_signature, jobject param_1); jobject CallObjectMethod(jobject callee, jclass callee_class, const char * method_name, const char * method_signature); jobject CallObjectMethod(jobject callee, jclass callee_class, const char * method_name, const char * method_signature, jobject param_1); jobject CallStaticObjectMethod(jclass callee_class, const char * method_name, const char * method_signature); jobject CallStaticObjectMethod(jclass callee_class, const char * method_name, const char * method_signature, jobject param_1); jobject CallStaticObjectMethod(jclass callee_class, const char * method_name, const char * method_signature, jobject param_1, jobject param_2, jobject param_3); jint CallIntMethod(jobject callee, jclass callee_class, const char * method_name, const char * method_signature, jobject param_1); void CallVoidMethod(jobject callee, jclass callee_class, const char * method_name, const char * method_signature); jstring NewStringUTF(const char * utf8_string); const char * GetStringUTFChars(jstring string); void ReleaseStringUTFChars(jstring string, const char * utf8_chars); jbyteArray NewByteArray(size_t size); jbyte * GetByteArrayElements(jbyteArray java_array); void ReleaseByteArrayElements(jbyteArray java_array, jbyte * native_array); private: void ThrowOnJavaException(); JavaVM * m_jvm = NULL; JNIEnv * m_env = NULL; bool m_needs_detaching = false;}; class JNIEnvWrapperException {}; JNIEnvWrapper::JNIEnvWrapper(JavaVM * jvm) : m_jvm(jvm){ int reason = jvm->GetEnv((void **)&m_env, JNI_VERSION_1_6); if( reason != JNI_OK && reason != JNI_EDETACHED ) { m_env = NULL; return; } if( reason == JNI_EDETACHED ) { if( jvm->AttachCurrentThread(&m_env, NULL) != 0 ) { m_env = NULL; return; } m_needs_detaching = true; } if( m_env->PushLocalFrame(32) != 0 ) { if( m_needs_detaching ) { m_jvm->DetachCurrentThread(); } m_env = NULL; }} JNIEnvWrapper::~JNIEnvWrapper(){ if( m_env == NULL ) { return; } m_env->PopLocalFrame(NULL); if( m_needs_detaching ) { m_jvm->DetachCurrentThread(); }} bool JNIEnvWrapper::IsValid() const{ return m_env != NULL;} void JNIEnvWrapper::ThrowOnJavaException(){ if( m_env->ExceptionCheck() ) { m_env->ExceptionDescribe(); m_env->ExceptionClear(); throw JNIEnvWrapperException(); }} jclass JNIEnvWrapper::FindClass(const char * class_signature){ jclass ret = m_env->FindClass(class_signature); ThrowOnJavaException(); return ret;} jobject JNIEnvWrapper::ConstructNewObject(jclass constructed_class, const char * constructor_signature, jobject param_1){ jmethodID method_id = m_env->GetMethodID(constructed_class, "<init>", constructor_signature); ThrowOnJavaException(); jobject ret = m_env->NewObject(constructed_class, method_id, param_1); ThrowOnJavaException(); return ret;} jobject JNIEnvWrapper::CallObjectMethod(jobject callee, jclass callee_class, const char * method_name, const char * method_signature){ jmethodID method_id = m_env->GetMethodID(callee_class, method_name, method_signature); ThrowOnJavaException(); jobject ret = m_env->CallObjectMethod(callee, method_id); ThrowOnJavaException(); return ret;} jobject JNIEnvWrapper::CallObjectMethod(jobject callee, jclass callee_class, const char * method_name, const char * method_signature, jobject param_1){ jmethodID method_id = m_env->GetMethodID(callee_class, method_name, method_signature); ThrowOnJavaException(); jobject ret = m_env->CallObjectMethod(callee, method_id, param_1); ThrowOnJavaException(); return ret;} jobject JNIEnvWrapper::CallStaticObjectMethod(jclass callee_class, const char * method_name, const char * method_signature){ jmethodID method_id = m_env->GetStaticMethodID(callee_class, method_name, method_signature); ThrowOnJavaException(); jobject ret = m_env->CallStaticObjectMethod(callee_class, method_id); ThrowOnJavaException(); return ret;} jobject JNIEnvWrapper::CallStaticObjectMethod(jclass callee_class, const char * method_name, const char * method_signature, jobject param_1){ jmethodID method_id = m_env->GetStaticMethodID(callee_class, method_name, method_signature); ThrowOnJavaException(); jobject ret = m_env->CallStaticObjectMethod(callee_class, method_id, param_1); ThrowOnJavaException(); return ret;} jobject JNIEnvWrapper::CallStaticObjectMethod(jclass callee_class, const char * method_name, const char * method_signature, jobject param_1, jobject param_2, jobject param_3){ jmethodID method_id = m_env->GetStaticMethodID(callee_class, method_name, method_signature); ThrowOnJavaException(); jobject ret = m_env->CallStaticObjectMethod(callee_class, method_id, param_1, param_2, param_3); ThrowOnJavaException(); return ret;} jint JNIEnvWrapper::CallIntMethod(jobject callee, jclass callee_class, const char * method_name, const char * method_signature, jobject param_1){ jmethodID method_id = m_env->GetMethodID(callee_class, method_name, method_signature); ThrowOnJavaException(); jint ret = m_env->CallIntMethod(callee, method_id, param_1); ThrowOnJavaException(); return ret;} void JNIEnvWrapper::CallVoidMethod(jobject callee, jclass callee_class, const char * method_name, const char * method_signature){ jmethodID method_id = m_env->GetMethodID(callee_class, method_name, method_signature); ThrowOnJavaException(); m_env->CallVoidMethod(callee, method_id); ThrowOnJavaException();} jstring JNIEnvWrapper::NewStringUTF(const char * utf8_string){ jstring ret = m_env->NewStringUTF(utf8_string); ThrowOnJavaException(); return ret;} const char * JNIEnvWrapper::GetStringUTFChars(jstring string){ return m_env->GetStringUTFChars(string, NULL);} void JNIEnvWrapper::ReleaseStringUTFChars(jstring string, const char * utf8_chars){ m_env->ReleaseStringUTFChars(string, utf8_chars);} jbyteArray JNIEnvWrapper::NewByteArray(size_t size){ jbyteArray ret = m_env->NewByteArray(size); ThrowOnJavaException(); return ret;} jbyte * JNIEnvWrapper::GetByteArrayElements(jbyteArray java_array){ return m_env->GetByteArrayElements(java_array, NULL);} void JNIEnvWrapper::ReleaseByteArrayElements(jbyteArray java_array, jbyte * native_array){ m_env->ReleaseByteArrayElements(java_array, native_array, 0);} static std::string GetTemporaryFilePath(JNIEnvWrapper& jni){ // context = android.app.ActivityThread.currentActivityThread().getApplication() jclass thread_class = jni.FindClass("android/app/ActivityThread"); jobject current_thread = jni.CallStaticObjectMethod(thread_class, "currentActivityThread", "()Landroid/app/ActivityThread;"); jobject context = jni.CallObjectMethod(current_thread, thread_class, "getApplication", "()Landroid/app/Application;"); // cache_dir = context.getCacheDir() jclass context_class = jni.FindClass("android/content/Context"); jobject cache_dir = jni.CallObjectMethod(context, context_class, "getCacheDir", "()Ljava/io/File;"); // temp_file = java.io.File.createTempFile("chuck_temp", "", cache_dir) jclass file_class = jni.FindClass("java/io/File"); jobject temp_file = jni.CallStaticObjectMethod(file_class, "createTempFile", "(Ljava/lang/String;Ljava/lang/String;Ljava/io/File;)Ljava/io/File;", jni.NewStringUTF("chuck_temp"), jni.NewStringUTF(""), cache_dir); // temp_file_path = temp_file.getPath() jstring temp_file_path = (jstring)jni.CallObjectMethod(temp_file, file_class, "getPath", "()Ljava/lang/String;"); const char * path_chars = jni.GetStringUTFChars(temp_file_path); std::string ret = path_chars; jni.ReleaseStringUTFChars(temp_file_path, path_chars); return ret;} FILE * ChuckAndroid::getTemporaryFile() noexcept{ JavaVM * jvm = getJVM(); if( !jvm ) { return NULL; } JNIEnvWrapper jni(jvm); if( !jni.IsValid() ) { return NULL; } try { const std::string temp_path = GetTemporaryFilePath(jni); return fopen(temp_path.c_str(), "wb+");Lines 1–500 of 613. Load more
/*---------------------------------------------------------------------------- ChucK Concurrent, On-the-fly Audio Programming Language Compiler and Virtual Machine Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved. http://chuck.stanford.edu/ http://chuck.cs.princeton.edu/ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 U.S.A. -----------------------------------------------------------------------------*/ //----------------------------------------------------------------------------- // name: util_platforms.cpp // desc: platform-specific utilities, e.g., for Android and various // // author: Andriy Kunitsyn (kunitzin@gmail.com) | original ChuckAndroid // Ge Wang (https://ccrma.stanford.edu/~ge/) // date: Summer 2021 //----------------------------------------------------------------------------- #include "util_platforms.h" #include "util_string.h" #include "chuck_errmsg.h" #ifdef __PLATFORM_WIN32__ #ifndef __CHUNREAL_ENGINE__ #include <windows.h> // for win32_tmpfile() #else // 1.5.0.0 (ge) | #chunreal // unreal engine on windows disallows including windows.h #include "Windows/MinWindows.h" #endif // #ifndef __CHUNREAL_ENGINE__ #endif // #ifdef __PLATFORM_WIN32__ #include <sys/stat.h> //----------------------------------------------------------------------------- // name: ck_openFileAutoExt() // desc: open a file by name, first as is, and if needed concatenateing ".ck" // this potentially modifies the contents of fname //----------------------------------------------------------------------------- FILE * ck_openFileAutoExt( std::string & filenameMutable, const std::string & extension ) { #ifdef __ANDROID__ if( strncmp(filenameMutable.c_str(), "jar:", strlen("jar:")) == 0 ) { int fd = 0; if( !ChuckAndroid::copyJARURLFileToTemporary(filenameMutable.c_str(), &fd) ) { EM_error2( 0, "unable to download from JAR URL: %s", filenameMutable.c_str() ); return NULL; } return fdopen(fd, "rb"); } #endif // __ANDROID__ // try opening FILE * fd = fopen( filenameMutable.c_str(), "rb" ); // file open? if( !fd ) { // check if filename has extension, ignoring case if( !extension_matches( filenameMutable, extension, TRUE ) ) { // concat std::string tryThis = filenameMutable + extension; // try opening again fd = fopen( tryThis.c_str(), "rb" ); // if successful update filename filenameMutable = tryThis; } } return fd; } //----------------------------------------------------------------------------- // name: win32_tmpfile() // desc: replacement for broken tmpfile() on Windows Vista + 7 //----------------------------------------------------------------------------- #ifdef __PLATFORM_WIN32__ FILE * win32_tmpfile() { char tmp_path[MAX_PATH]; char file_path[MAX_PATH]; FILE * file = NULL; #ifndef __CHUNREAL_ENGINE__ if( GetTempPath(256, tmp_path) == 0 ) #else // 1.5.0.0 (ge) | #chunreal explicit call ASCII version if( GetTempPathA(256, tmp_path) == 0 ) #endif return NULL; #ifndef __CHUNREAL_ENGINE__ if( GetTempFileName(tmp_path, "mA", 0, file_path) == 0 ) #else // 1.5.0.0 (ge) | #chunreal explicit call ASCII version if( GetTempFileNameA(tmp_path, "mA", 0, file_path) == 0 ) #endif return NULL; file = fopen( file_path, "wb+D" ); return file; } #endif // #ifdef __PLATFORM_WIN32__ //----------------------------------------------------------------------------- // name: android_tmpfile() // desc: replacement for broken tmpfile() on Android //----------------------------------------------------------------------------- #ifdef __ANDROID__ FILE * android_tmpfile() { return ChuckAndroid::getTemporaryFile(); } #endif //----------------------------------------------------------------------------- // name: android_tmpfile() // desc: replacement for broken tmpfile() on Android //----------------------------------------------------------------------------- FILE * ck_tmpfile() { FILE * fd = NULL; #ifdef __PLATFORM_WIN32__ fd = win32_tmpfile(); #elif defined (__ANDROID__) fd = android_tmpfile(); #else fd = tmpfile(); #endif return fd; } //----------------------------------------------------------------------------- // name: ck_isdir() // desc: check if file is a directory //----------------------------------------------------------------------------- t_CKBOOL ck_isdir( const std::string & path ) { // shuttle struct stat fs; // stat the path and check flag (is path not there, also returns false) return (stat( path.c_str(), &fs )==0 && fs.st_mode & S_IFDIR); } //----------------------------------------------------------------------------- #ifdef __ANDROID__ //----------------------------------------------------------------------------- #include <jni.h> #include <fcntl.h> #include <unistd.h> #include <string> static JavaVM * jvm_instance = NULL; JNIEXPORT jint JNICALL JNI_OnLoad( JavaVM * vm, void * reserved ) { jvm_instance = vm; return JNI_VERSION_1_6; } JavaVM * ChuckAndroid::getJVM() { return jvm_instance; } //----------------------------------------------------------------------------- // name: class JNIEnvWrapper // desc: Wrapper around JNIEnv. Serves three purposes: // - releases JNIEnv and Java objects in RAII fashion // - removes the need to get method IDs // - throws JNIEnvWrapperException exception on Java exceptions //----------------------------------------------------------------------------- class JNIEnvWrapper { public: JNIEnvWrapper(JavaVM * jvm); ~JNIEnvWrapper(); bool IsValid() const; jclass FindClass(const char * class_signature); jobject ConstructNewObject(jclass constructed_class, const char * constructor_signature, jobject param_1); jobject CallObjectMethod(jobject callee, jclass callee_class, const char * method_name, const char * method_signature); jobject CallObjectMethod(jobject callee, jclass callee_class, const char * method_name, const char * method_signature, jobject param_1); jobject CallStaticObjectMethod(jclass callee_class, const char * method_name, const char * method_signature); jobject CallStaticObjectMethod(jclass callee_class, const char * method_name, const char * method_signature, jobject param_1); jobject CallStaticObjectMethod(jclass callee_class, const char * method_name, const char * method_signature, jobject param_1, jobject param_2, jobject param_3); jint CallIntMethod(jobject callee, jclass callee_class, const char * method_name, const char * method_signature, jobject param_1); void CallVoidMethod(jobject callee, jclass callee_class, const char * method_name, const char * method_signature); jstring NewStringUTF(const char * utf8_string); const char * GetStringUTFChars(jstring string); void ReleaseStringUTFChars(jstring string, const char * utf8_chars); jbyteArray NewByteArray(size_t size); jbyte * GetByteArrayElements(jbyteArray java_array); void ReleaseByteArrayElements(jbyteArray java_array, jbyte * native_array); private: void ThrowOnJavaException(); JavaVM * m_jvm = NULL; JNIEnv * m_env = NULL; bool m_needs_detaching = false; }; class JNIEnvWrapperException {}; JNIEnvWrapper::JNIEnvWrapper(JavaVM * jvm) : m_jvm(jvm) { int reason = jvm->GetEnv((void **)&m_env, JNI_VERSION_1_6); if( reason != JNI_OK && reason != JNI_EDETACHED ) { m_env = NULL; return; } if( reason == JNI_EDETACHED ) { if( jvm->AttachCurrentThread(&m_env, NULL) != 0 ) { m_env = NULL; return; } m_needs_detaching = true; } if( m_env->PushLocalFrame(32) != 0 ) { if( m_needs_detaching ) { m_jvm->DetachCurrentThread(); } m_env = NULL; } } JNIEnvWrapper::~JNIEnvWrapper() { if( m_env == NULL ) { return; } m_env->PopLocalFrame(NULL); if( m_needs_detaching ) { m_jvm->DetachCurrentThread(); } } bool JNIEnvWrapper::IsValid() const { return m_env != NULL; } void JNIEnvWrapper::ThrowOnJavaException() { if( m_env->ExceptionCheck() ) { m_env->ExceptionDescribe(); m_env->ExceptionClear(); throw JNIEnvWrapperException(); } } jclass JNIEnvWrapper::FindClass(const char * class_signature) { jclass ret = m_env->FindClass(class_signature); ThrowOnJavaException(); return ret; } jobject JNIEnvWrapper::ConstructNewObject(jclass constructed_class, const char * constructor_signature, jobject param_1) { jmethodID method_id = m_env->GetMethodID(constructed_class, "<init>", constructor_signature); ThrowOnJavaException(); jobject ret = m_env->NewObject(constructed_class, method_id, param_1); ThrowOnJavaException(); return ret; } jobject JNIEnvWrapper::CallObjectMethod(jobject callee, jclass callee_class, const char * method_name, const char * method_signature) { jmethodID method_id = m_env->GetMethodID(callee_class, method_name, method_signature); ThrowOnJavaException(); jobject ret = m_env->CallObjectMethod(callee, method_id); ThrowOnJavaException(); return ret; } jobject JNIEnvWrapper::CallObjectMethod(jobject callee, jclass callee_class, const char * method_name, const char * method_signature, jobject param_1) { jmethodID method_id = m_env->GetMethodID(callee_class, method_name, method_signature); ThrowOnJavaException(); jobject ret = m_env->CallObjectMethod(callee, method_id, param_1); ThrowOnJavaException(); return ret; } jobject JNIEnvWrapper::CallStaticObjectMethod(jclass callee_class, const char * method_name, const char * method_signature) { jmethodID method_id = m_env->GetStaticMethodID(callee_class, method_name, method_signature); ThrowOnJavaException(); jobject ret = m_env->CallStaticObjectMethod(callee_class, method_id); ThrowOnJavaException(); return ret; } jobject JNIEnvWrapper::CallStaticObjectMethod(jclass callee_class, const char * method_name, const char * method_signature, jobject param_1) { jmethodID method_id = m_env->GetStaticMethodID(callee_class, method_name, method_signature); ThrowOnJavaException(); jobject ret = m_env->CallStaticObjectMethod(callee_class, method_id, param_1); ThrowOnJavaException(); return ret; } jobject JNIEnvWrapper::CallStaticObjectMethod(jclass callee_class, const char * method_name, const char * method_signature, jobject param_1, jobject param_2, jobject param_3) { jmethodID method_id = m_env->GetStaticMethodID(callee_class, method_name, method_signature); ThrowOnJavaException(); jobject ret = m_env->CallStaticObjectMethod(callee_class, method_id, param_1, param_2, param_3); ThrowOnJavaException(); return ret; } jint JNIEnvWrapper::CallIntMethod(jobject callee, jclass callee_class, const char * method_name, const char * method_signature, jobject param_1) { jmethodID method_id = m_env->GetMethodID(callee_class, method_name, method_signature); ThrowOnJavaException(); jint ret = m_env->CallIntMethod(callee, method_id, param_1); ThrowOnJavaException(); return ret; } void JNIEnvWrapper::CallVoidMethod(jobject callee, jclass callee_class, const char * method_name, const char * method_signature) { jmethodID method_id = m_env->GetMethodID(callee_class, method_name, method_signature); ThrowOnJavaException(); m_env->CallVoidMethod(callee, method_id); ThrowOnJavaException(); } jstring JNIEnvWrapper::NewStringUTF(const char * utf8_string) { jstring ret = m_env->NewStringUTF(utf8_string); ThrowOnJavaException(); return ret; } const char * JNIEnvWrapper::GetStringUTFChars(jstring string) { return m_env->GetStringUTFChars(string, NULL); } void JNIEnvWrapper::ReleaseStringUTFChars(jstring string, const char * utf8_chars) { m_env->ReleaseStringUTFChars(string, utf8_chars); } jbyteArray JNIEnvWrapper::NewByteArray(size_t size) { jbyteArray ret = m_env->NewByteArray(size); ThrowOnJavaException(); return ret; } jbyte * JNIEnvWrapper::GetByteArrayElements(jbyteArray java_array) { return m_env->GetByteArrayElements(java_array, NULL); } void JNIEnvWrapper::ReleaseByteArrayElements(jbyteArray java_array, jbyte * native_array) { m_env->ReleaseByteArrayElements(java_array, native_array, 0); } static std::string GetTemporaryFilePath(JNIEnvWrapper& jni) { // context = android.app.ActivityThread.currentActivityThread().getApplication() jclass thread_class = jni.FindClass("android/app/ActivityThread"); jobject current_thread = jni.CallStaticObjectMethod(thread_class, "currentActivityThread", "()Landroid/app/ActivityThread;"); jobject context = jni.CallObjectMethod(current_thread, thread_class, "getApplication", "()Landroid/app/Application;"); // cache_dir = context.getCacheDir() jclass context_class = jni.FindClass("android/content/Context"); jobject cache_dir = jni.CallObjectMethod(context, context_class, "getCacheDir", "()Ljava/io/File;"); // temp_file = java.io.File.createTempFile("chuck_temp", "", cache_dir) jclass file_class = jni.FindClass("java/io/File"); jobject temp_file = jni.CallStaticObjectMethod(file_class, "createTempFile", "(Ljava/lang/String;Ljava/lang/String;Ljava/io/File;)Ljava/io/File;", jni.NewStringUTF("chuck_temp"), jni.NewStringUTF(""), cache_dir); // temp_file_path = temp_file.getPath() jstring temp_file_path = (jstring)jni.CallObjectMethod(temp_file, file_class, "getPath", "()Ljava/lang/String;"); const char * path_chars = jni.GetStringUTFChars(temp_file_path); std::string ret = path_chars; jni.ReleaseStringUTFChars(temp_file_path, path_chars); return ret; } FILE * ChuckAndroid::getTemporaryFile() noexcept { JavaVM * jvm = getJVM(); if( !jvm ) { return NULL; } JNIEnvWrapper jni(jvm); if( !jni.IsValid() ) { return NULL; } try { const std::string temp_path = GetTemporaryFilePath(jni); return fopen(temp_path.c_str(), "wb+");