const char* environment_home_directory( void ) { if( _environment_home_dir[0] ) return _environment_home_dir; #if FOUNDATION_PLATFORM_WINDOWS { char* path; wchar_t* wpath = memory_allocate_zero( sizeof( wchar_t ) * FOUNDATION_MAX_PATHLEN, 0, MEMORY_TEMPORARY ); SHGetFolderPathW( 0, CSIDL_LOCAL_APPDATA, 0, 0, wpath ); path = path_clean( string_allocate_from_wstring( wpath, 0 ), true ); string_copy( _environment_home_dir, path, FOUNDATION_MAX_PATHLEN ); string_deallocate( path ); memory_deallocate( wpath ); } #elif FOUNDATION_PLATFORM_LINUX string_copy( _environment_home_dir, environment_variable( "HOME" ), FOUNDATION_MAX_PATHLEN ); #elif FOUNDATION_PLATFORM_APPLE if( environment_application()->flags & APPLICATION_UTILITY ) { CFStringRef home = NSHomeDirectory(); CFStringGetCString( home, _environment_home_dir, FOUNDATION_MAX_PATHLEN, kCFStringEncodingUTF8 ); } else { char bundle_identifier[FOUNDATION_MAX_PATHLEN+1]; environment_bundle_identifier( bundle_identifier ); char* path = path_append( path_merge( _environment_home_dir, "/Library/Application Support" ), bundle_identifier ); string_copy( _environment_home_dir, path, FOUNDATION_MAX_PATHLEN ); string_deallocate( path ); } #elif FOUNDATION_PLATFORM_ANDROID string_copy( _environment_home_dir, android_app()->activity->internalDataPath, FOUNDATION_MAX_PATHLEN ); #else # error Not implemented #endif return _environment_home_dir; }
char *arUtilGetResourcesDirectoryPath(AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR behavior) #endif { #ifndef _WINRT char *wpath1; char *wpath2; # ifdef _WIN32 DWORD len; # endif #endif AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR behaviorW; if (behavior == AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_BEST) { #if defined(__APPLE__) behaviorW = AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_BUNDLE_RESOURCES_DIR; #elif defined(ANDROID) behaviorW = AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_APP_CACHE_DIR; #elif defined(_WIN32) || defined(__linux) behaviorW = AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_EXECUTABLE_DIR; #else behaviorW = AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_CWD; #endif } else { behaviorW = behavior; } switch (behaviorW) { case AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_EXECUTABLE_DIR: #if (defined(_WIN32) && !defined(_WINRT)) || defined(__APPLE__) || defined(__linux) arMallocClear(wpath1, char, MAXPATHLEN); # if defined(_WIN32) len = GetModuleFileName(NULL, wpath1, MAXPATHLEN); // NULL implies the current process. if (!len) { free (wpath1); return (NULL); } # elif defined(__APPLE__) uint32_t size = MAXPATHLEN; if (_NSGetExecutablePath(wpath1, &size) != 0) { free (wpath1); return (NULL); } # elif defined(__linux) ssize_t len; len = readlink("/proc/self/exe", wpath1, MAXPATHLEN - 1); // -1 as it is not NULL terminated. if (len == -1) { ARLOGperror(NULL); free (wpath1); return (NULL); } wpath1[len] = '\0'; // NULL terminate. # endif arMallocClear(wpath2, char, MAXPATHLEN); if (!arUtilGetDirectoryNameFromPath(wpath2, wpath1, MAXPATHLEN, 0)) { free (wpath1); free (wpath2); return (NULL); } free (wpath1); return (wpath2); #else return (NULL); // Unsupported OS. #endif break; case AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_BUNDLE_RESOURCES_DIR: #if defined(__APPLE__) { // Change working directory to resources directory inside app bundle. wpath1 = NULL; CFURLRef pathCFURLRef = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); // Get relative path to resources directory. if (pathCFURLRef) { wpath1 = (char *)calloc(MAXPATHLEN, sizeof(char)); //getcwd(path, MAXPATHLEN); if (wpath1) { if (!CFURLGetFileSystemRepresentation(pathCFURLRef, true, (UInt8*)wpath1, MAXPATHLEN)) { // true in param 2 resolves against base. ARLOGe("Error: Unable to get file system representation of a CFURL.\n"); free(wpath1); wpath1 = NULL; } } CFRelease(pathCFURLRef); } return (wpath1); } #else return (NULL); // Unsupported OS. #endif break; case AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_CWD: #ifndef _WINRT arMallocClear(wpath1, char, MAXPATHLEN); if (!getcwd(wpath1, MAXPATHLEN)) { free(wpath1); return (NULL); } return (wpath1); #else return (NULL); // Unsupported OS. #endif break; case AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_USER_ROOT: #if defined(_WIN32) && !defined(_WINRT) arMallocClear(wpath1, char, MAXPATHLEN); if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, 0, wpath1))) { free (wpath1); return (NULL); } return (wpath1); #elif defined(ANDROID) { // Make JNI calls to get the external storage directory. // To begin, get a reference to the env and attach to it. JNIEnv *env; int isAttached = 0; jthrowable exception; if (((*gJavaVM)->GetEnv(gJavaVM, (void**)&env, JNI_VERSION_1_6)) < 0) { // Couldn't get JNI environment, so this thread is native. if (((*gJavaVM)->AttachCurrentThread(gJavaVM, &env, NULL)) < 0) { ARLOGe("Error: Couldn't attach to Java VM.\n"); return (NULL); } isAttached = 1; } // Get File object for the external storage directory. jclass classEnvironment = (*env)->FindClass(env, "android/os/Environment"); if (!classEnvironment) goto bailAndroid; jmethodID methodIDgetExternalStorageDirectory = (*env)->GetStaticMethodID(env, classEnvironment, "getExternalStorageDirectory", "()Ljava/io/File;"); // public static File getExternalStorageDirectory () if (!methodIDgetExternalStorageDirectory) goto bailAndroid; jobject objectFile = (*env)->CallStaticObjectMethod(env, classEnvironment, methodIDgetExternalStorageDirectory); exception = (*env)->ExceptionOccurred(env); if (exception) { (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); } // Call method on File object to retrieve String object. jclass classFile = (*env)->GetObjectClass(env, objectFile); if (!classFile) goto bailAndroid; jmethodID methodIDgetAbsolutePath = (*env)->GetMethodID(env, classFile, "getAbsolutePath", "()Ljava/lang/String;"); if (!methodIDgetAbsolutePath) goto bailAndroid; jstring stringPath = (*env)->CallObjectMethod(env, objectFile, methodIDgetAbsolutePath); exception = (*env)->ExceptionOccurred(env); if (exception) { (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); } // Extract a C string from the String object and copy it. const char *wpath3 = (*env)->GetStringUTFChars(env, stringPath, NULL); wpath1 = strdup(wpath3); (*env)->ReleaseStringUTFChars(env, stringPath, wpath3); goto retAndroid; bailAndroid: ARLOGe("Error: JNI call failure.\n"); wpath1 = NULL; retAndroid: if (isAttached) (*gJavaVM)->DetachCurrentThread(gJavaVM); // Clean up. return (wpath1); } #elif defined(__APPLE__) && defined(__OBJC__) // iOS/OS X. { NSString *nssHomeDir = NSHomeDirectory(); // CoreFoundation equivalent is CFCopyHomeDirectoryURL(), iOS 6.0+ only. if (!nssHomeDir) { return (NULL); } wpath1 = strdup([nssHomeDir UTF8String]); return wpath1; } #elif defined(__linux) if (!((wpath1 = getenv("HOME")))) { return (NULL); } return (strdup(wpath1)); #else return (NULL); // Unsupported OS. #endif break; case AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_APP_CACHE_DIR: #if defined(_WIN32) return (NULL); #elif defined(__APPLE__) // iOS/OS X. { # ifdef __OBJC__ NSURL *cacheDir = [[[NSFileManager defaultManager] URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask] objectAtIndex:0]; if (!cacheDir) { return (NULL); } wpath1 = strdup([[cacheDir path] UTF8String]); # else size_t len = confstr(_CS_DARWIN_USER_CACHE_DIR, NULL, 0); if (!len) return (NULL); wpath1 = (char *)malloc(len); len = confstr(_CS_DARWIN_USER_CACHE_DIR, wpath1, len); // On OS X, returns a folder in the sandbox hierachy under /var/folders/. if (!len) return (NULL); # endif return (wpath1); } #elif defined(ANDROID) { // Make JNI calls to get the Context's cache directory. // To begin, get a reference to the env and attach to it. JNIEnv *env; int isAttached = 0; int ret = 0; jthrowable exception; if (((*gJavaVM)->GetEnv(gJavaVM, (void**)&env, JNI_VERSION_1_6)) < 0) { // Couldn't get JNI environment, so this thread is native. if (((*gJavaVM)->AttachCurrentThread(gJavaVM, &env, NULL)) < 0) { ARLOGe("Error: Couldn't attach to Java VM.\n"); return (NULL); } isAttached = 1; } // Get File object for the Context's files directory. This only works // if a subclass of Context is supplied. // e.g. JNIEXPORT void JNICALL Java_com_test_TestActivity_test(JNIEnv * env, jobject obj) // so make sure before call. jclass classOfSuppliedObject = (*env)->GetObjectClass(env, instanceOfAndroidContext); if (!classOfSuppliedObject) goto bailAndroid1; jclass classContext = (*env)->FindClass(env, "android/content/Context"); if (!classContext) goto bailAndroid1; if (!(*env)->IsInstanceOf(env, instanceOfAndroidContext, classContext)) { ARLOGe("Error: supplied object is not an instance of android/content/Context.\n"); wpath1 = NULL; // Bad parameter. goto retAndroid1; } jmethodID methodGetDir = (*env)->GetMethodID(env, classOfSuppliedObject, "getCacheDir", "()Ljava/io/File;"); // public abstract File getCacheDir(); //jmethodID methodGetDir = (*env)->GetMethodID(env, classOfSuppliedObject, "getFilesDir", "(Ljava/lang/String;)Ljava/io/File;"); // public abstract File getFilesDir(String type); if (!methodGetDir) goto bailAndroid1; jobject objectFile = (*env)->CallObjectMethod(env, instanceOfAndroidContext, methodGetDir); exception = (*env)->ExceptionOccurred(env); if (exception) { (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); } // Call method on File object to retrieve String object. jclass classFile = (*env)->GetObjectClass(env, objectFile); if (!classFile) goto bailAndroid1; jmethodID methodIDgetAbsolutePath = (*env)->GetMethodID(env, classFile, "getAbsolutePath", "()Ljava/lang/String;"); if (!methodIDgetAbsolutePath) goto bailAndroid1; jstring stringPath = (*env)->CallObjectMethod(env, objectFile, methodIDgetAbsolutePath); exception = (*env)->ExceptionOccurred(env); if (exception) { (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); } // Extract a C string from the String object, and chdir() to it. const char *wpath3 = (*env)->GetStringUTFChars(env, stringPath, NULL); wpath1 = strdup(wpath3); (*env)->ReleaseStringUTFChars(env, stringPath, wpath3); goto retAndroid1; bailAndroid1: ARLOGe("Error: JNI call failure.\n"); wpath1 = NULL; retAndroid1: if (isAttached) (*gJavaVM)->DetachCurrentThread(gJavaVM); // Clean up. return (wpath1); } #else return (NULL); // Unsupported OS. #endif break; case AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_APP_DATA_DIR: #ifdef _WINRT //auto folder = Windows::Storage::ApplicationData::Current->LocalFolder; //wpath1 = strdup(folder->Path->Data().c_str()); //return (wpath1); return (NULL); // Unsupported OS. #else return (NULL); // Unsupported OS. #endif break; case AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_SUPPLIED_PATH: default: return (NULL); // Undefined behaviour. break; } }