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;
}
示例#2
0
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;
    }
}