/* * Apple platform (macOS, iOS, watchOS, etc) 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_APPLE #include #include #include "physfs_internal.h" int __PHYSFS_platformInit(void) { return 1; /* success. */ } /* __PHYSFS_platformInit */ void __PHYSFS_platformDeinit(void) { /* no-op */ } /* __PHYSFS_platformDeinit */ char *__PHYSFS_platformCalcBaseDir(const char *argv0) { @autoreleasepool { NSString *path = [[NSBundle mainBundle] bundlePath]; BAIL_IF(!path, PHYSFS_ERR_OS_ERROR, NULL); size_t len = [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; char *retval = (char *) allocator.Malloc(len + 2); BAIL_IF(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL); [path getCString:retval maxLength:len+1 encoding:NSUTF8StringEncoding]; retval[len] = '/'; retval[len+1] = '\0'; return retval; /* whew. */ } /* @autoreleasepool */ } /* __PHYSFS_platformCalcBaseDir */ char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app) { @autoreleasepool { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, TRUE); BAIL_IF(!paths, PHYSFS_ERR_OS_ERROR, NULL); NSString *path = (NSString *) [paths objectAtIndex:0]; BAIL_IF(!path, PHYSFS_ERR_OS_ERROR, NULL); size_t len = [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; const size_t applen = strlen(app); char *retval = (char *) allocator.Malloc(len + applen + 3); BAIL_IF(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL); [path getCString:retval maxLength:len+1 encoding:NSUTF8StringEncoding]; snprintf(retval + len, applen + 3, "/%s/", app); return retval; /* whew. */ } /* @autoreleasepool */ } /* __PHYSFS_platformCalcPrefDir */ /* CD-ROM detection code... */ /* * Code based on sample from Apple Developer Connection: * https://developer.apple.com/samplecode/Sample_Code/Devices_and_Hardware/Disks/VolumeToBSDNode/VolumeToBSDNode.c.htm */ #if !defined(PHYSFS_NO_CDROM_SUPPORT) #include #include #include #include #include static int darwinIsWholeMedia(io_service_t service) { int retval = 0; CFTypeRef wholeMedia; if (!IOObjectConformsTo(service, kIOMediaClass)) return 0; wholeMedia = IORegistryEntryCreateCFProperty(service, CFSTR(kIOMediaWholeKey), NULL, 0); if (wholeMedia == NULL) return 0; retval = CFBooleanGetValue(wholeMedia); CFRelease(wholeMedia); return retval; } /* darwinIsWholeMedia */ static int darwinIsMountedDisc(char *bsdName, mach_port_t mainPort) { int retval = 0; CFMutableDictionaryRef matchingDict; kern_return_t rc; io_iterator_t iter; io_service_t service; if ((matchingDict = IOBSDNameMatching(mainPort, 0, bsdName)) == NULL) return 0; rc = IOServiceGetMatchingServices(mainPort, 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 */ #endif /* !defined(PHYSFS_NO_CDROM_SUPPORT) */ void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data) { #if !defined(PHYSFS_NO_CDROM_SUPPORT) /* macOS 12.0 changed "master" names to "main". */ typedef kern_return_t (*ioMainPortFn)(mach_port_t, mach_port_t *); static ioMainPortFn ioMainPort = NULL; const char *devPrefix = "/dev/"; const int prefixLen = strlen(devPrefix); mach_port_t mainPort = 0; struct statfs *mntbufp; int i, mounts; if (ioMainPort == NULL) { ioMainPort = (ioMainPortFn) dlsym(RTLD_DEFAULT, "IOMainPort"); if (!ioMainPort) ioMainPort = (ioMainPortFn) dlsym(RTLD_DEFAULT, "IOMasterPort"); if (!ioMainPort) return; /* oh well, no CD-ROMs for you. */ } /* if */ if (ioMainPort(MACH_PORT_NULL, &mainPort) != KERN_SUCCESS) BAIL(PHYSFS_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, mainPort)) cb(data, mnt); } /* for */ #endif /* !defined(PHYSFS_NO_CDROM_SUPPORT) */ } /* __PHYSFS_platformDetectAvailableCDs */ #endif /* PHYSFS_PLATFORM_APPLE */ /* end of physfs_platform_apple.m ... */