Split out Mac OS X code from unix.c and added some Carbon-specific code...
authorRyan C. Gordon <icculus@icculus.org>
Wed, 21 Mar 2007 05:03:17 +0000
changeset 847 5e5e6c067413
parent 846 df684fce470e
child 848 963d26edb39b
Split out Mac OS X code from unix.c and added some Carbon-specific code... moved some stuff around and implemented a few things in BeOS and POSIX bits to accomodate this.
CMakeLists.txt
physfs_platforms.h
platform/beos.cpp
platform/macosx.c
platform/posix.c
platform/unix.c
--- a/CMakeLists.txt	Wed Mar 21 04:31:13 2007 +0000
+++ b/CMakeLists.txt	Wed Mar 21 05:03:17 2007 +0000
@@ -117,6 +117,7 @@
     platform/pocketpc.c
     platform/posix.c
     platform/unix.c
+    platform/macosx.c
     platform/windows.c
     archivers/dir.c
     archivers/grp.c
--- a/physfs_platforms.h	Wed Mar 21 04:31:13 2007 +0000
+++ b/physfs_platforms.h	Wed Mar 21 05:03:17 2007 +0000
@@ -23,7 +23,6 @@
 #  define PHYSFS_PLATFORM_OS2
 #elif ((defined __MACH__) && (defined __APPLE__))
 #  define PHYSFS_PLATFORM_MACOSX
-#  define PHYSFS_PLATFORM_UNIX
 #  define PHYSFS_PLATFORM_POSIX
 #elif defined(macintosh)
 #  error Classic Mac OS support was dropped from PhysicsFS 2.0. Move to OS X.
--- a/platform/beos.cpp	Wed Mar 21 04:31:13 2007 +0000
+++ b/platform/beos.cpp	Wed Mar 21 05:03:17 2007 +0000
@@ -30,9 +30,6 @@
 #include "physfs_internal.h"
 
 
-const char *__PHYSFS_platformDirSeparator = "/";
-
-
 int __PHYSFS_platformInit(void)
 {
     return(1);  /* always succeed. */
@@ -158,7 +155,7 @@
     thread_id tid = find_thread(NULL);
     get_thread_info(tid, &info);
     return(info.team);
-} /* getMyTeamID */
+} /* getTeamID */
 
 
 char *__PHYSFS_platformCalcBaseDir(const char *argv0)
@@ -201,6 +198,12 @@
 } /* __PHYSFS_platformRealPath */
 
 
+char *__PHYSFS_platformCurrentDir(void)
+{
+    return(__PHYSFS_platformRealPath("."));  /* let BPath sort it out. */
+} /* __PHYSFS_platformCurrentDir */
+
+
 /* !!! FIXME: semaphores are not mutexes... */
 void *__PHYSFS_platformCreateMutex(void)
 {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/platform/macosx.c	Wed Mar 21 05:03:17 2007 +0000
@@ -0,0 +1,396 @@
+/*
+ * Mac OS X support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_MACOSX
+
+#include <Carbon/Carbon.h>
+#include <IOKit/storage/IOMedia.h>
+#include <IOKit/storage/IOCDMedia.h>
+#include <IOKit/storage/IODVDMedia.h>
+#include <sys/mount.h>
+
+/* Seems to get defined in some system header... */
+#ifdef Free
+#undef Free
+#endif
+
+#include "physfs_internal.h"
+
+
+/* Wrap PHYSFS_Allocator in a CFAllocator... */
+static CFAllocatorRef cfallocator = NULL;
+
+CFStringRef cfallocDesc(const void *info)
+{
+    return(CFStringCreateWithCString(cfallocator, "PhysicsFS",
+                                     kCFStringEncodingASCII));
+} /* cfallocDesc */
+
+
+static void *cfallocMalloc(CFIndex allocSize, CFOptionFlags hint, void *info)
+{
+    return allocator.Malloc(allocSize);
+} /* cfallocMalloc */
+
+
+static void cfallocFree(void *ptr, void *info)
+{
+    allocator.Free(ptr);
+} /* cfallocFree */
+
+
+static void *cfallocRealloc(void *ptr, CFIndex newsize,
+                            CFOptionFlags hint, void *info)
+{
+    if ((ptr == NULL) || (newsize <= 0))
+        return NULL;  /* ADC docs say you should always return NULL here. */
+    return allocator.Realloc(ptr, newsize);
+} /* cfallocRealloc */
+
+
+int __PHYSFS_platformInit(void)
+{
+    /* set up a CFAllocator, so Carbon can use the physfs allocator, too. */
+    CFAllocatorContext ctx;
+    memset(&ctx, '\0', sizeof (ctx));
+    ctx.copyDescription = cfallocDesc;
+    ctx.allocate = cfallocMalloc;
+    ctx.reallocate = cfallocRealloc;
+    ctx.deallocate = cfallocFree;
+    cfallocator = CFAllocatorCreate(kCFAllocatorUseContext, &ctx);
+    BAIL_IF_MACRO(cfallocator == NULL, ERR_OUT_OF_MEMORY, 0);
+    return(1);  /* success. */
+} /* __PHYSFS_platformInit */
+
+
+int __PHYSFS_platformDeinit(void)
+{
+    CFRelease(cfallocator);
+    cfallocator = NULL;
+    return(1);  /* always succeed. */
+} /* __PHYSFS_platformDeinit */
+
+
+/* CD-ROM detection code... */
+
+/*
+ * Code based on sample from Apple Developer Connection:
+ *  http://developer.apple.com/samplecode/Sample_Code/Devices_and_Hardware/Disks/VolumeToBSDNode/VolumeToBSDNode.c.htm
+ */
+
+static int darwinIsWholeMedia(io_service_t service)
+{
+    int retval = 0;
+    CFTypeRef wholeMedia;
+
+    if (!IOObjectConformsTo(service, kIOMediaClass))
+        return(0);
+        
+    wholeMedia = IORegistryEntryCreateCFProperty(service,
+                                                 CFSTR(kIOMediaWholeKey),
+                                                 cfallocator, 0);
+    if (wholeMedia == NULL)
+        return(0);
+
+    retval = CFBooleanGetValue(wholeMedia);
+    CFRelease(wholeMedia);
+
+    return retval;
+} /* darwinIsWholeMedia */
+
+
+static int darwinIsMountedDisc(char *bsdName, mach_port_t masterPort)
+{
+    int retval = 0;
+    CFMutableDictionaryRef matchingDict;
+    kern_return_t rc;
+    io_iterator_t iter;
+    io_service_t service;
+
+    if ((matchingDict = IOBSDNameMatching(masterPort, 0, bsdName)) == NULL)
+        return(0);
+
+    rc = IOServiceGetMatchingServices(masterPort, matchingDict, &iter);
+    if ((rc != KERN_SUCCESS) || (!iter))
+        return(0);
+
+    service = IOIteratorNext(iter);
+    IOObjectRelease(iter);
+    if (!service)
+        return(0);
+
+    rc = IORegistryEntryCreateIterator(service, kIOServicePlane,
+             kIORegistryIterateRecursively | kIORegistryIterateParents, &iter);
+    
+    if (!iter)
+        return(0);
+
+    if (rc != KERN_SUCCESS)
+    {
+        IOObjectRelease(iter);
+        return(0);
+    } /* if */
+
+    IOObjectRetain(service);  /* add an extra object reference... */
+
+    do
+    {
+        if (darwinIsWholeMedia(service))
+        {
+            if ( (IOObjectConformsTo(service, kIOCDMediaClass)) ||
+                 (IOObjectConformsTo(service, kIODVDMediaClass)) )
+            {
+                retval = 1;
+            } /* if */
+        } /* if */
+        IOObjectRelease(service);
+    } while ((service = IOIteratorNext(iter)) && (!retval));
+                
+    IOObjectRelease(iter);
+    IOObjectRelease(service);
+
+    return(retval);
+} /* darwinIsMountedDisc */
+
+
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
+{
+    const char *devPrefix = "/dev/";
+    const int prefixLen = strlen(devPrefix);
+    mach_port_t masterPort = 0;
+    struct statfs *mntbufp;
+    int i, mounts;
+
+    if (IOMasterPort(MACH_PORT_NULL, &masterPort) != KERN_SUCCESS)
+        BAIL_MACRO(ERR_OS_ERROR, /*return void*/);
+
+    mounts = getmntinfo(&mntbufp, MNT_WAIT);  /* NOT THREAD SAFE! */
+    for (i = 0; i < mounts; i++)
+    {
+        char *dev = mntbufp[i].f_mntfromname;
+        char *mnt = mntbufp[i].f_mntonname;
+        if (strncmp(dev, devPrefix, prefixLen) != 0)  /* a virtual device? */
+            continue;
+
+        dev += prefixLen;
+        if (darwinIsMountedDisc(dev, masterPort))
+            cb(data, mnt);
+    } /* for */
+} /* __PHYSFS_platformDetectAvailableCDs */
+
+
+static char *convertCFString(CFStringRef cfstr)
+{
+    CFIndex len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
+                                                    kCFStringEncodingUTF8) + 1;
+    char *retval = (char *) allocator.Malloc(len);
+    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    if (CFStringGetCString(cfstr, retval, len, kCFStringEncodingUTF8))
+    {
+        /* shrink overallocated buffer if possible... */
+        CFIndex newlen = strlen(retval) + 1;
+        if (newlen < len)
+        {
+            void *ptr = allocator.Realloc(retval, newlen);
+            if (ptr != NULL)
+                retval = (char *) ptr;
+        } /* if */
+    } /* if */
+
+    else  /* probably shouldn't fail, but just in case... */
+    {
+        allocator.Free(retval);
+        BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
+    } /* else */
+
+    return(retval);
+} /* convertCFString */
+
+
+char *__PHYSFS_platformCalcBaseDir(const char *argv0)
+{
+    ProcessSerialNumber psn = { 0, kCurrentProcess };
+    FSRef fsref;
+    CFRange cfrange;
+    CFURLRef cfurl = NULL;
+    CFStringRef cfstr = NULL;
+    CFMutableStringRef cfmutstr = NULL;
+    char *retval = NULL;
+
+    BAIL_IF_MACRO(GetProcessBundleLocation(&psn, &fsref) != noErr, NULL, NULL);
+    cfurl = CFURLCreateFromFSRef(cfallocator, &fsref);
+    BAIL_IF_MACRO(cfurl == NULL, NULL, NULL);
+    cfstr = CFURLCopyFileSystemPath(cfurl, kCFURLPOSIXPathStyle);
+    CFRelease(cfurl);
+    BAIL_IF_MACRO(cfstr == NULL, NULL, NULL);
+    cfmutstr = CFStringCreateMutableCopy(cfallocator, 0, cfstr);
+    CFRelease(cfstr);
+    BAIL_IF_MACRO(cfmutstr == NULL, NULL, NULL);
+
+    /* Find last dirsep so we can chop the binary's filename from the path. */
+    cfrange = CFStringFind(cfmutstr, CFSTR("/"), kCFCompareBackwards);
+    if (cfrange.location == kCFNotFound)
+    {
+        assert(0);  /* shouldn't ever hit this... */
+        CFRelease(cfmutstr);
+        return(NULL);
+    } /* if */
+
+    /* chop the "/exename" from the end of the path string... */
+    cfrange.length = CFStringGetLength(cfmutstr) - cfrange.location;
+    CFStringDelete(cfmutstr, cfrange);
+
+    /* If we're an Application Bundle, chop everything but the base. */
+    cfrange = CFStringFind(cfmutstr, CFSTR("/Contents/MacOS"),
+                           kCFCompareCaseInsensitive |
+                           kCFCompareBackwards |
+                           kCFCompareAnchored);
+
+    if (cfrange.location != kCFNotFound)
+        CFStringDelete(cfmutstr, cfrange);  /* chop that, too. */
+
+    retval = convertCFString(cfmutstr);
+    CFRelease(cfmutstr);
+
+    return(retval);  /* whew. */
+} /* __PHYSFS_platformCalcBaseDir */
+
+
+/* !!! FIXME */
+#define osxerr(x) x
+
+char *__PHYSFS_platformRealPath(const char *path)
+{
+    /* The symlink and relative path resolving happens in FSPathMakeRef() */
+    FSRef fsref;
+    CFURLRef cfurl = NULL;
+    CFStringRef cfstr = NULL;
+    char *retval = NULL;
+    OSStatus rc = osxerr(FSPathMakeRef((UInt8 *) path, &fsref, NULL));
+    BAIL_IF_MACRO(rc != noErr, NULL, NULL);
+
+    /* Now get it to spit out a full path. */
+    cfurl = CFURLCreateFromFSRef(cfallocator, &fsref);
+    BAIL_IF_MACRO(cfurl == NULL, ERR_OUT_OF_MEMORY, NULL);
+    cfstr = CFURLCopyFileSystemPath(cfurl, kCFURLPOSIXPathStyle);
+    CFRelease(cfurl);
+    BAIL_IF_MACRO(cfstr == NULL, ERR_OUT_OF_MEMORY, NULL);
+    retval = convertCFString(cfstr);
+    CFRelease(cfstr);
+
+    return(retval);
+} /* __PHYSFS_platformRealPath */
+
+
+char *__PHYSFS_platformCurrentDir(void)
+{
+    return(__PHYSFS_platformRealPath("."));  /* let CFURL sort it out. */
+} /* __PHYSFS_platformCurrentDir */
+
+
+/* Platform allocator uses default CFAllocator at PHYSFS_init() time. */
+
+static CFAllocatorRef cfallocdef = NULL;
+
+static int macosxAllocatorInit(void)
+{
+    int retval = 0;
+    cfallocdef = CFAllocatorGetDefault();
+    retval = (cfallocdef != NULL);
+    if (retval)
+        CFRetain(cfallocdef);
+    return(retval);
+} /* macosxAllocatorInit */
+
+
+static void macosxAllocatorDeinit(void)
+{
+    if (cfallocdef != NULL)
+    {
+        CFRelease(cfallocdef);
+        cfallocdef = NULL;
+    } /* if */
+} /* macosxAllocatorDeinit */
+
+
+static void *macosxAllocatorMalloc(PHYSFS_uint64 s)
+{
+    BAIL_IF_MACRO(__PHYSFS_ui64FitsAddressSpace(s), ERR_OUT_OF_MEMORY, NULL);
+    return(CFAllocatorAllocate(cfallocdef, (CFIndex) s, 0));
+} /* macosxAllocatorMalloc */
+
+
+static void *macosxAllocatorRealloc(void *ptr, PHYSFS_uint64 s)
+{
+    BAIL_IF_MACRO(__PHYSFS_ui64FitsAddressSpace(s), ERR_OUT_OF_MEMORY, NULL);
+    return(CFAllocatorReallocate(cfallocdef, ptr, (CFIndex) s, 0));
+} /* macosxAllocatorRealloc */
+
+
+static void macosxAllocatorFree(void *ptr)
+{
+    CFAllocatorDeallocate(cfallocdef, ptr);
+} /* macosxAllocatorFree */
+
+
+int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
+{
+    allocator.Init = macosxAllocatorInit;
+    allocator.Deinit = macosxAllocatorDeinit;
+    allocator.Malloc = macosxAllocatorMalloc;
+    allocator.Realloc = macosxAllocatorRealloc;
+    allocator.Free = macosxAllocatorFree;
+    return(1);  /* return non-zero: we're supplying custom allocator. */
+} /* __PHYSFS_platformSetDefaultAllocator */
+
+
+PHYSFS_uint64 __PHYSFS_platformGetThreadID(void)
+{
+    return( (PHYSFS_uint64) ((size_t) MPCurrentTaskID()) );
+} /* __PHYSFS_platformGetThreadID */
+
+
+void *__PHYSFS_platformCreateMutex(void)
+{
+    MPCriticalRegionID m = NULL;
+    if (osxerr(MPCreateCriticalRegion(&m)) != noErr)
+        return NULL;
+    return m;
+} /* __PHYSFS_platformCreateMutex */
+
+
+void __PHYSFS_platformDestroyMutex(void *mutex)
+{
+    MPCriticalRegionID m = (MPCriticalRegionID) mutex;
+    MPDeleteCriticalRegion(m);
+} /* __PHYSFS_platformDestroyMutex */
+
+
+int __PHYSFS_platformGrabMutex(void *mutex)
+{
+    MPCriticalRegionID m = (MPCriticalRegionID) mutex;
+    if (MPEnterCriticalRegion(m, kDurationForever) != noErr)
+        return(0);
+    return(1);
+} /* __PHYSFS_platformGrabMutex */
+
+
+void __PHYSFS_platformReleaseMutex(void *mutex)
+{
+    MPCriticalRegionID m = (MPCriticalRegionID) mutex;
+    MPExitCriticalRegion(m);
+} /* __PHYSFS_platformReleaseMutex */
+
+#endif /* PHYSFS_PLATFORM_MACOSX */
+
+/* end of macosx.c ... */
+
--- a/platform/posix.c	Wed Mar 21 04:31:13 2007 +0000
+++ b/platform/posix.c	Wed Mar 21 05:03:17 2007 +0000
@@ -30,6 +30,9 @@
 #include "physfs_internal.h"
 
 
+const char *__PHYSFS_platformDirSeparator = "/";
+
+
 char *__PHYSFS_platformCopyEnvironmentVariable(const char *varname)
 {
     const char *envr = getenv(varname);
@@ -224,43 +227,6 @@
 } /* __PHYSFS_platformEnumerateFiles */
 
 
-char *__PHYSFS_platformCurrentDir(void)
-{
-    int allocSize = 0;
-    char *retval = NULL;
-    char *ptr;
-
-    do
-    {
-        allocSize += 100;
-        ptr = (char *) allocator.Realloc(retval, allocSize);
-        if (ptr == NULL)
-        {
-            if (retval != NULL)
-                allocator.Free(retval);
-            BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
-        } /* if */
-
-        retval = ptr;
-        ptr = getcwd(retval, allocSize);
-    } while (ptr == NULL && errno == ERANGE);
-
-    if (ptr == NULL && errno)
-    {
-            /*
-             * getcwd() failed for some reason, for example current
-             * directory not existing.
-             */
-        if (retval != NULL)
-            allocator.Free(retval);
-        BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
-    } /* if */
-
-    return(retval);
-} /* __PHYSFS_platformCurrentDir */
-
-
-
 int __PHYSFS_platformMkDir(const char *path)
 {
     int rc;
--- a/platform/unix.c	Wed Mar 21 04:31:13 2007 +0000
+++ b/platform/unix.c	Wed Mar 21 05:03:17 2007 +0000
@@ -25,15 +25,6 @@
 #include <errno.h>
 #include <sys/mount.h>
 
-#ifdef PHYSFS_PLATFORM_MACOSX
-#  include <CoreFoundation/CoreFoundation.h>
-#  include <CoreServices/CoreServices.h>
-#  include <IOKit/IOKitLib.h>
-#  include <IOKit/storage/IOMedia.h>
-#  include <IOKit/storage/IOCDMedia.h>
-#  include <IOKit/storage/IODVDMedia.h>
-#endif
-
 #if (!defined PHYSFS_NO_PTHREADS_SUPPORT)
 #include <pthread.h>
 #endif
@@ -51,13 +42,6 @@
 
 #include "physfs_internal.h"
 
-/* Seems to get defined in some system header... */
-#ifdef Free
-#undef Free
-#endif
-
-const char *__PHYSFS_platformDirSeparator = "/";
-
 
 int __PHYSFS_platformInit(void)
 {
@@ -78,113 +62,6 @@
 {
 } /* __PHYSFS_platformDetectAvailableCDs */
 
-
-#elif (defined PHYSFS_PLATFORM_MACOSX)  /* "Big Nasty." */
-/*
- * Code based on sample from Apple Developer Connection:
- *  http://developer.apple.com/samplecode/Sample_Code/Devices_and_Hardware/Disks/VolumeToBSDNode/VolumeToBSDNode.c.htm
- */
-
-static int darwinIsWholeMedia(io_service_t service)
-{
-    int retval = 0;
-    CFTypeRef wholeMedia;
-
-    if (!IOObjectConformsTo(service, kIOMediaClass))
-        return(0);
-        
-    wholeMedia = IORegistryEntryCreateCFProperty(service,
-                                                 CFSTR(kIOMediaWholeKey),
-                                                 kCFAllocatorDefault, 0);
-    if (wholeMedia == NULL)
-        return(0);
-
-    retval = CFBooleanGetValue(wholeMedia);
-    CFRelease(wholeMedia);
-
-    return retval;
-} /* darwinIsWholeMedia */
-
-
-static int darwinIsMountedDisc(char *bsdName, mach_port_t masterPort)
-{
-    int retval = 0;
-    CFMutableDictionaryRef matchingDict;
-    kern_return_t rc;
-    io_iterator_t iter;
-    io_service_t service;
-
-    if ((matchingDict = IOBSDNameMatching(masterPort, 0, bsdName)) == NULL)
-        return(0);
-
-    rc = IOServiceGetMatchingServices(masterPort, matchingDict, &iter);
-    if ((rc != KERN_SUCCESS) || (!iter))
-        return(0);
-
-    service = IOIteratorNext(iter);
-    IOObjectRelease(iter);
-    if (!service)
-        return(0);
-
-    rc = IORegistryEntryCreateIterator(service, kIOServicePlane,
-             kIORegistryIterateRecursively | kIORegistryIterateParents, &iter);
-    
-    if (!iter)
-        return(0);
-
-    if (rc != KERN_SUCCESS)
-    {
-        IOObjectRelease(iter);
-        return(0);
-    } /* if */
-
-    IOObjectRetain(service);  /* add an extra object reference... */
-
-    do
-    {
-        if (darwinIsWholeMedia(service))
-        {
-            if ( (IOObjectConformsTo(service, kIOCDMediaClass)) ||
-                 (IOObjectConformsTo(service, kIODVDMediaClass)) )
-            {
-                retval = 1;
-            } /* if */
-        } /* if */
-        IOObjectRelease(service);
-    } while ((service = IOIteratorNext(iter)) && (!retval));
-                
-    IOObjectRelease(iter);
-    IOObjectRelease(service);
-
-    return(retval);
-} /* darwinIsMountedDisc */
-
-
-void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
-{
-    const char *devPrefix = "/dev/";
-    int prefixLen = strlen(devPrefix);
-    mach_port_t masterPort = 0;
-    struct statfs *mntbufp;
-    int i, mounts;
-
-    if (IOMasterPort(MACH_PORT_NULL, &masterPort) != KERN_SUCCESS)
-        BAIL_MACRO(ERR_OS_ERROR, /*return void*/);
-
-    mounts = getmntinfo(&mntbufp, MNT_WAIT);  /* NOT THREAD SAFE! */
-    for (i = 0; i < mounts; i++)
-    {
-        char *dev = mntbufp[i].f_mntfromname;
-        char *mnt = mntbufp[i].f_mntonname;
-        if (strncmp(dev, devPrefix, prefixLen) != 0)  /* a virtual device? */
-            continue;
-
-        dev += prefixLen;
-        if (darwinIsMountedDisc(dev, masterPort))
-            cb(data, mnt);
-    } /* for */
-} /* __PHYSFS_platformDetectAvailableCDs */
-
 #elif (defined PHYSFS_HAVE_SYS_UCRED_H)
 
 void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
@@ -350,107 +227,6 @@
 } /* __PHYSFS_platformCalcBaseDir */
 
 
-#ifdef PHYSFS_PLATFORM_MACOSX
-/* 
- * 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;
-    size_t len = strlen(path) + 1;
-    int i;
-    
-    /* !!! FIXME: Can we stack-allocate this? --ryan. */
-    tempbuf = (char *) allocator.Malloc(len);
-    if (!tempbuf) return;
-    memset(tempbuf, '\0', len);
-
-    /* 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 */
-        allocator.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';
-    }
-    allocator.Free(tempbuf);
-    return;
-}
-#endif
-
-
 char *__PHYSFS_platformRealPath(const char *path)
 {
     char resolved_path[MAXPATHLEN];
@@ -462,15 +238,51 @@
     BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
     strcpy(retval, resolved_path);
 
-/* !!! FIXME: this shouldn't be here. */
-#ifdef PHYSFS_PLATFORM_MACOSX
-    stripAppleBundle(retval);
-#endif
-    
     return(retval);
 } /* __PHYSFS_platformRealPath */
 
 
+char *__PHYSFS_platformCurrentDir(void)
+{
+    /*
+     * This can't just do platformRealPath("."), since that would eventually
+     *  just end up calling back into here.
+     */
+
+    int allocSize = 0;
+    char *retval = NULL;
+    char *ptr;
+
+    do
+    {
+        allocSize += 100;
+        ptr = (char *) allocator.Realloc(retval, allocSize);
+        if (ptr == NULL)
+        {
+            if (retval != NULL)
+                allocator.Free(retval);
+            BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
+        } /* if */
+
+        retval = ptr;
+        ptr = getcwd(retval, allocSize);
+    } while (ptr == NULL && errno == ERANGE);
+
+    if (ptr == NULL && errno)
+    {
+            /*
+             * getcwd() failed for some reason, for example current
+             * directory not existing.
+             */
+        if (retval != NULL)
+            allocator.Free(retval);
+        BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
+    } /* if */
+
+    return(retval);
+} /* __PHYSFS_platformCurrentDir */
+
+
 int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
 {
     return(0);  /* just use malloc() and friends. */