Added hack for OSX bundles, from Eric Wing.
authorRyan C. Gordon <icculus@icculus.org>
Sat, 04 Jan 2003 23:24:50 +0000
changeset 520 a72bbf255074
parent 519 c16b1af0919f
child 521 61846d1430aa
Added hack for OSX bundles, from Eric Wing.
platform/unix.c
--- a/platform/unix.c	Tue Dec 17 23:55:03 2002 +0000
+++ b/platform/unix.c	Sat Jan 04 23:24:50 2003 +0000
@@ -266,6 +266,103 @@
 } /* __PHYSFS_platformTimeslice */
 
 
+#if defined(__MACH__) && defined(__APPLE__)
+/* 
+ * This function is only for OSX. The problem is that Apple's applications
+ * can actually be directory structures with the actual executable nested
+ * several levels down. PhysFS computes the base directory from the Unix
+ * executable, but this may not be the correct directory. Apple tries to
+ * hide everything from the user, so from Finder, the user never sees the
+ * Unix executable, and the directory package (bundle) is considered the
+ * "executable". This means that the correct base directory is at the 
+ * level where the directory structure starts.
+ * A typical bundle seems to look like this:
+ * MyApp.app/    <-- top level...this is what the user sees in Finder 
+ *   Contents/
+ *     MacOS/
+ *       MyApp   <-- the actual executable
+ *       
+ * Since anything below the app folder is considered hidden, most 
+ * application files need to be at the top level if you intend to
+ * write portable software. Thus if the application resides in:
+ * /Applications/MyProgram
+ * and the executable is the bundle MyApp.app,
+ * PhysFS computes the following as the base directory:
+ * /Applications/MyProgram/MyApp.app/Contents/MacOS/
+ * We need to strip off the MyApp.app/Contents/MacOS/
+ * 
+ * However, there are corner cases. OSX applications can be traditional
+ * Unix executables without the bundle. Also, it is not entirely clear
+ * to me what kinds of permutations bundle structures can have.
+ * 
+ * For now, this is a temporary hack until a better solution 
+ * can be made. This function will try to find a "/Contents/MacOS"
+ * inside the path. If it succeeds, then the path will be truncated
+ * to correct the directory. If it is not found, the path will be 
+ * left alone and will presume it is a traditional Unix execuatable.
+ * Most programs also include the .app extention in the top level
+ * folder, but it doesn't seem to be a requirement (Acrobat doesn't 
+ * have it). MacOS looks like it can also be MacOSClassic. 
+ * This function will test for MacOS and hope it captures any
+ * other permutations.
+ */
+static void stripAppleBundle(char *path)
+{
+    char *sub_str = "/contents/macos";
+    char *found_ptr = NULL;
+    char *tempbuf = NULL;
+    int i;
+    
+    /* Calloc will place the \0 character in the proper place for us */
+    tempbuf = (char*)calloc( (strlen(path)+1), sizeof(char) );
+    /* Unlike other Unix filesystems, HFS is case insensitive
+     * It wouldn be nice to use strcasestr, but it doesn't seem
+     * to be available in the OSX gcc library right now.
+     * So we should make a lower case copy of the path to 
+     * compare against 
+     */
+    for(i=0; i<strlen(path); i++)
+    {
+        /* convert to lower case */
+        tempbuf[i] = tolower(path[i]);
+    }
+    /* See if we can find "/contents/macos" in the path */
+    found_ptr = strstr(tempbuf, sub_str);
+    if(NULL == found_ptr)
+    {
+        /* It doesn't look like a bundle so we can keep the 
+         * original path. Just return */
+        free(tempbuf);
+        return;
+    }
+    /* We have a bundle, so let's backstep character by character
+     * to erase the extra parts of the path. Quit when we hit
+     * the preceding '/' character.
+     */
+    for(i=strlen(path)-strlen(found_ptr)-1; i>=0; i--)
+    {
+        if('/' == path[i])
+        {
+            break;
+        }
+    }
+    /* Safety check */
+    if(i<1)
+    {
+        /* This probably shouldn't happen. */
+        path[0] = '\0';
+    }
+    else
+    {
+        /* Back up one more to remove trailing '/' and set the '\0' */
+        path[i] = '\0';
+    }
+    free(tempbuf);
+    return;
+}
+#endif /* defined __MACH__ && defined __APPLE__ */
+
+
 char *__PHYSFS_platformRealPath(const char *path)
 {
     char resolved_path[MAXPATHLEN];
@@ -276,6 +373,11 @@
     retval = (char *) malloc(strlen(resolved_path) + 1);
     BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
     strcpy(retval, resolved_path);
+
+#if defined(__MACH__) && defined(__APPLE__)
+    stripAppleBundle(retval);
+#endif /* defined __MACH__ && defined __APPLE__ */
+    
     return(retval);
 } /* __PHYSFS_platformRealPath */