int VirtualEnvironmentInit(const char *objectListFile) { int numObjects; FILE *fp; char buf[MAXPATHLEN]; char objectFullpath[MAXPATHLEN]; int i; ARdouble translation[3], rotation[4], scale[3]; int lightingFlag, markerIndex; ARLOGd("Initialising Virtual Environment.\n"); // One-time OSG initialization. if (!VirtualEnvironment_AROSG) { VirtualEnvironment_AROSG = arOSGInit(); if (!VirtualEnvironment_AROSG) { ARLOGe("Error: unable to init arOSG library.\n"); return (0); } } // Locate and open the objects description file. if ((fp = fopen(objectListFile, "r")) == NULL) { ARLOGe("Error: unable to open object data file '%s'.\n", objectListFile); perror(NULL); goto bail1; } else { ARLOGe("Error: open object data file '%s'.\n", objectListFile); } // First line is number of objects to read. numObjects = 0; get_buff(buf, MAXPATHLEN, fp, 1); if (sscanf(buf, "%d", &numObjects) != 1) { ARLOGe("Error: unable to read number of objects to load from object data file.\n"); goto bail2; } // Allocate space for the objects. if (objects) { free(objects); objects = NULL; objectCount = 0; } objects = (VEObject*)calloc(numObjects, sizeof(VEObject)); if (!objects) { goto bail2; } ARLOGd("Reading %d objects.\n", numObjects); for (i = 0; i < numObjects; i++) { // Read in all info relating to the object. // Read model file path (relative to objects description file). if (!get_buff(buf, MAXPATHLEN, fp, 1)) { ARLOGe("Error: unable to read model file name from object data file.\n"); goto bail3; } if (!arUtilGetDirectoryNameFromPath(objectFullpath, objectListFile, sizeof(objectFullpath), 1)) // Get directory prefix, with path separator. { goto bail3; } strncat(objectFullpath, buf, sizeof(objectFullpath) - strlen(objectFullpath) - 1); // Add name of file to open. // Read translation. get_buff(buf, MAXPATHLEN, fp, 1); #ifdef ARDOUBLE_IS_FLOAT if (sscanf(buf, "%f %f %f", &translation[0], &translation[1], &translation[2]) != 3) #else if (sscanf(buf, "%lf %lf %lf", &translation[0], &translation[1], &translation[2]) != 3) #endif { goto bail3; } // Read rotation. get_buff(buf, MAXPATHLEN, fp, 1); #ifdef ARDOUBLE_IS_FLOAT if (sscanf(buf, "%f %f %f %f", &rotation[0], &rotation[1], &rotation[2], &rotation[3]) != 4) #else if (sscanf(buf, "%lf %lf %lf %lf", &rotation[0], &rotation[1], &rotation[2], &rotation[3]) != 4) #endif { goto bail3; } // Read scale. get_buff(buf, MAXPATHLEN, fp, 1); #ifdef ARDOUBLE_IS_FLOAT if (sscanf(buf, "%f %f %f", &scale[0], &scale[1], &scale[2]) != 3) #else if (sscanf(buf, "%lf %lf %lf", &scale[0], &scale[1], &scale[2]) != 3) #endif { goto bail3; } // Look for optional tokens. A blank line marks end of options. lightingFlag = 1; markerIndex = -1; while (get_buff(buf, MAXPATHLEN, fp, 0) && (buf[0] != '\0')) { if (strncmp(buf, "LIGHTING", 8) == 0) { if (sscanf(&(buf[8]), " %d", &lightingFlag) != 1) { ARLOGe("Error in object file: LIGHTING token must be followed by an integer >= 0. Discarding.\n"); } } else if (strncmp(buf, "MARKER", 6) == 0) { if (sscanf(&(buf[6]), " %d", &markerIndex) != 1) { ARLOGe("Error in object file: MARKER token must be followed by an integer > 0. Discarding.\n"); } else { markerIndex--; // Marker numbers are zero-indexed, but in the config file they're 1-indexed. } } // Unknown tokens are ignored. } // Now attempt to load objects. ARLOGd("Reading object data file %s.\n", objectFullpath); objects[i].modelIndex = arOSGLoadModel2(VirtualEnvironment_AROSG, objectFullpath, translation, rotation, scale); if (objects[i].modelIndex < 0) { ARLOGe("Error attempting to read object data file %s.\n", objectFullpath); goto bail4; } // Set optional properties. arOSGSetModelLighting(VirtualEnvironment_AROSG, objects[i].modelIndex, lightingFlag); // If a valid marker index has been specified, save it. if (markerIndex >= 0 /*&& markerIndex < markersCount]*/) { arOSGSetModelVisibility(VirtualEnvironment_AROSG, objects[i].modelIndex, FALSE); // Objects tied to markers will not be initially visible. objects[i].markerIndex = markerIndex; } else { arOSGSetModelVisibility(VirtualEnvironment_AROSG, objects[i].modelIndex, TRUE); // All other objects will be initially visible. objects[i].markerIndex = -1; } objectCount++; } ARLOGd("Virtual Environment initialised.\n"); fclose(fp); return (objectCount); bail4: for (i--; i >= 0; i--) { arOSGUnloadModel(VirtualEnvironment_AROSG, i); } bail3: free(objects); objects = NULL; objectCount = 0; bail2: fclose(fp); bail1: if (VirtualEnvironment_AROSG) { arOSGFinal(VirtualEnvironment_AROSG); VirtualEnvironment_AROSG = NULL; } #ifdef DEBUG ARLOGe("Virtual Environment initialisation failed.\n"); #endif return (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: return (NULL); // Unsupported OS. 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(__linux) || defined(__APPLE__) 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(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; } }
ARMultiMarkerInfoT *arMultiReadConfigFile( const char *filename, ARPattHandle *pattHandle ) { FILE *fp; ARMultiEachMarkerInfoT *marker; ARMultiMarkerInfoT *marker_info; ARdouble wpos3d[4][2]; char buf[256], pattPath[2048], dummy; int num; int patt_type = 0; int i, j; if ((fp = fopen(filename, "r")) == NULL) { ARLOGe("Error: unable to open multimarker config file '%s'.\n", filename); ARLOGperror(NULL); return NULL; } get_buff(buf, 256, fp); if( sscanf(buf, "%d", &num) != 1 ) { ARLOGe("Error processing multimarker config file '%s': First line must be number of marker configs to read.\n", filename); fclose(fp); return NULL; } ARLOGd("Reading %d markers from multimarker file '%s'\n", num, filename); arMalloc(marker, ARMultiEachMarkerInfoT, num); for( i = 0; i < num; i++ ) { get_buff(buf, 256, fp); if (sscanf(buf, #if defined(__LP64__) && !defined(__APPLE__) "%lu%c", #else "%llu%c", #endif &(marker[i].globalID), &dummy) != 1) { // Try first as matrix code. if (!pattHandle) { ARLOGe("Error processing multimarker config file '%s': pattern '%s' specified in multimarker configuration while in barcode-only mode.\n", filename, buf); goto bail; } if (!arUtilGetDirectoryNameFromPath(pattPath, filename, sizeof(pattPath), 1)) { // Get directory prefix. ARLOGe("Error processing multimarker config file '%s': Unable to determine directory name.\n", filename); goto bail; } strncat(pattPath, buf, sizeof(pattPath) - strlen(pattPath) - 1); // Add name of file to open. if ((marker[i].patt_id = arPattLoad(pattHandle, pattPath)) < 0) { ARLOGe("Error processing multimarker config file '%s': Unable to load pattern '%s'.\n", filename, pattPath); goto bail; } marker[i].patt_type = AR_MULTI_PATTERN_TYPE_TEMPLATE; patt_type |= 0x01; } else { if ((marker[i].globalID & 0xffff8000ULL) == 0ULL) marker[i].patt_id = (int)(marker[i].globalID & 0x00007fffULL); // If upper 33 bits are zero, use lower 31 bits as regular matrix code. else marker[i].patt_id = 0; ARLOGd("Marker %3d is matrix code %llu.\n", i + 1, marker[i].globalID); marker[i].patt_type = AR_MULTI_PATTERN_TYPE_MATRIX; patt_type |= 0x02; } get_buff(buf, 256, fp); if( sscanf(buf, #ifdef ARDOUBLE_IS_FLOAT "%f", #else "%lf", #endif &marker[i].width) != 1 ) { ARLOGe("Error processing multimarker config file '%s', marker definition %3d: First line must be pattern width.\n", filename, i + 1); goto bail; } j = 0; get_buff(buf, 256, fp); if( sscanf(buf, #ifdef ARDOUBLE_IS_FLOAT "%f %f %f %f", #else "%lf %lf %lf %lf", #endif &marker[i].trans[j][0], &marker[i].trans[j][1], &marker[i].trans[j][2], &marker[i].trans[j][3]) != 4 ) { // Perhaps this is an old ARToolKit v2.x multimarker file? // If so, then the next line is two values (center) and should be skipped. float t1, t2; if( sscanf(buf, "%f %f", &t1, &t2) != 2 ) { ARLOGe("Error processing multimarker config file '%s', marker definition %3d: Lines 2 - 4 must be marker transform.\n", filename, i + 1); goto bail; } } else j++; do { get_buff(buf, 256, fp); if( sscanf(buf, #ifdef ARDOUBLE_IS_FLOAT "%f %f %f %f", #else "%lf %lf %lf %lf", #endif &marker[i].trans[j][0], &marker[i].trans[j][1], &marker[i].trans[j][2], &marker[i].trans[j][3]) != 4 ) { ARLOGe("Error processing multimarker config file '%s', marker definition %3d: Lines 2 - 4 must be marker transform.\n", filename, i + 1); goto bail; } j++; } while (j < 3); arUtilMatInv( (const ARdouble (*)[4])marker[i].trans, marker[i].itrans ); wpos3d[0][0] = -marker[i].width/2.0; wpos3d[0][1] = marker[i].width/2.0; wpos3d[1][0] = marker[i].width/2.0; wpos3d[1][1] = marker[i].width/2.0; wpos3d[2][0] = marker[i].width/2.0; wpos3d[2][1] = -marker[i].width/2.0; wpos3d[3][0] = -marker[i].width/2.0; wpos3d[3][1] = -marker[i].width/2.0; for( j = 0; j < 4; j++ ) { marker[i].pos3d[j][0] = marker[i].trans[0][0] * wpos3d[j][0] + marker[i].trans[0][1] * wpos3d[j][1] + marker[i].trans[0][3]; marker[i].pos3d[j][1] = marker[i].trans[1][0] * wpos3d[j][0] + marker[i].trans[1][1] * wpos3d[j][1] + marker[i].trans[1][3]; marker[i].pos3d[j][2] = marker[i].trans[2][0] * wpos3d[j][0] + marker[i].trans[2][1] * wpos3d[j][1] + marker[i].trans[2][3]; } } fclose(fp); arMalloc(marker_info, ARMultiMarkerInfoT, 1); marker_info->marker = marker; marker_info->marker_num = num; marker_info->prevF = 0; if( (patt_type & 0x03) == 0x03 ) marker_info->patt_type = AR_MULTI_PATTERN_DETECTION_MODE_TEMPLATE_AND_MATRIX; else if( patt_type & 0x01 ) marker_info->patt_type = AR_MULTI_PATTERN_DETECTION_MODE_TEMPLATE; else marker_info->patt_type = AR_MULTI_PATTERN_DETECTION_MODE_MATRIX; marker_info->cfPattCutoff = AR_MULTI_CONFIDENCE_PATTERN_CUTOFF_DEFAULT; marker_info->cfMatrixCutoff = AR_MULTI_CONFIDENCE_MATRIX_CUTOFF_DEFAULT; return marker_info; bail: fclose(fp); free(marker); return NULL; }
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; } }