physfs_platform_apple.m 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /*
  2. * Apple platform (macOS, iOS, watchOS, etc) support routines for PhysicsFS.
  3. *
  4. * Please see the file LICENSE.txt in the source's root directory.
  5. *
  6. * This file written by Ryan C. Gordon.
  7. */
  8. #define __PHYSICSFS_INTERNAL__
  9. #include "physfs_platforms.h"
  10. #ifdef PHYSFS_PLATFORM_APPLE
  11. #include <Foundation/Foundation.h>
  12. #include <dlfcn.h>
  13. #include "physfs_internal.h"
  14. int __PHYSFS_platformInit(const char *argv0)
  15. {
  16. return 1; /* success. */
  17. } /* __PHYSFS_platformInit */
  18. void __PHYSFS_platformDeinit(void)
  19. {
  20. /* no-op */
  21. } /* __PHYSFS_platformDeinit */
  22. char *__PHYSFS_platformCalcBaseDir(const char *argv0)
  23. {
  24. @autoreleasepool
  25. {
  26. NSString *path = [[NSBundle mainBundle] bundlePath];
  27. BAIL_IF(!path, PHYSFS_ERR_OS_ERROR, NULL);
  28. size_t len = [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
  29. char *retval = (char *) allocator.Malloc(len + 2);
  30. BAIL_IF(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
  31. [path getCString:retval maxLength:len+1 encoding:NSUTF8StringEncoding];
  32. retval[len] = '/';
  33. retval[len+1] = '\0';
  34. return retval; /* whew. */
  35. } /* @autoreleasepool */
  36. } /* __PHYSFS_platformCalcBaseDir */
  37. char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
  38. {
  39. @autoreleasepool
  40. {
  41. NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, TRUE);
  42. BAIL_IF(!paths, PHYSFS_ERR_OS_ERROR, NULL);
  43. NSString *path = (NSString *) [paths objectAtIndex:0];
  44. BAIL_IF(!path, PHYSFS_ERR_OS_ERROR, NULL);
  45. size_t len = [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
  46. const size_t applen = strlen(app);
  47. char *retval = (char *) allocator.Malloc(len + applen + 3);
  48. BAIL_IF(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
  49. [path getCString:retval maxLength:len+1 encoding:NSUTF8StringEncoding];
  50. snprintf(retval + len, applen + 3, "/%s/", app);
  51. return retval; /* whew. */
  52. } /* @autoreleasepool */
  53. } /* __PHYSFS_platformCalcPrefDir */
  54. /* CD-ROM detection code... */
  55. /*
  56. * Code based on sample from Apple Developer Connection:
  57. * https://developer.apple.com/samplecode/Sample_Code/Devices_and_Hardware/Disks/VolumeToBSDNode/VolumeToBSDNode.c.htm
  58. */
  59. #if !defined(PHYSFS_NO_CDROM_SUPPORT)
  60. #include <IOKit/IOKitLib.h>
  61. #include <IOKit/storage/IOMedia.h>
  62. #include <IOKit/storage/IOCDMedia.h>
  63. #include <IOKit/storage/IODVDMedia.h>
  64. #include <sys/mount.h>
  65. static int darwinIsWholeMedia(io_service_t service)
  66. {
  67. int retval = 0;
  68. CFTypeRef wholeMedia;
  69. if (!IOObjectConformsTo(service, kIOMediaClass))
  70. return 0;
  71. wholeMedia = IORegistryEntryCreateCFProperty(service,
  72. CFSTR(kIOMediaWholeKey),
  73. NULL, 0);
  74. if (wholeMedia == NULL)
  75. return 0;
  76. retval = CFBooleanGetValue(wholeMedia);
  77. CFRelease(wholeMedia);
  78. return retval;
  79. } /* darwinIsWholeMedia */
  80. static int darwinIsMountedDisc(char *bsdName, mach_port_t mainPort)
  81. {
  82. int retval = 0;
  83. CFMutableDictionaryRef matchingDict;
  84. kern_return_t rc;
  85. io_iterator_t iter;
  86. io_service_t service;
  87. if ((matchingDict = IOBSDNameMatching(mainPort, 0, bsdName)) == NULL)
  88. return 0;
  89. rc = IOServiceGetMatchingServices(mainPort, matchingDict, &iter);
  90. if ((rc != KERN_SUCCESS) || (!iter))
  91. return 0;
  92. service = IOIteratorNext(iter);
  93. IOObjectRelease(iter);
  94. if (!service)
  95. return 0;
  96. rc = IORegistryEntryCreateIterator(service, kIOServicePlane,
  97. kIORegistryIterateRecursively | kIORegistryIterateParents, &iter);
  98. if (!iter)
  99. return 0;
  100. if (rc != KERN_SUCCESS)
  101. {
  102. IOObjectRelease(iter);
  103. return 0;
  104. } /* if */
  105. IOObjectRetain(service); /* add an extra object reference... */
  106. do
  107. {
  108. if (darwinIsWholeMedia(service))
  109. {
  110. if ( (IOObjectConformsTo(service, kIOCDMediaClass)) ||
  111. (IOObjectConformsTo(service, kIODVDMediaClass)) )
  112. {
  113. retval = 1;
  114. } /* if */
  115. } /* if */
  116. IOObjectRelease(service);
  117. } while ((service = IOIteratorNext(iter)) && (!retval));
  118. IOObjectRelease(iter);
  119. IOObjectRelease(service);
  120. return retval;
  121. } /* darwinIsMountedDisc */
  122. #endif /* !defined(PHYSFS_NO_CDROM_SUPPORT) */
  123. void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
  124. {
  125. #if !defined(PHYSFS_NO_CDROM_SUPPORT)
  126. /* macOS 12.0 changed "master" names to "main". */
  127. typedef kern_return_t (*ioMainPortFn)(mach_port_t, mach_port_t *);
  128. static ioMainPortFn ioMainPort = NULL;
  129. const char *devPrefix = "/dev/";
  130. const int prefixLen = strlen(devPrefix);
  131. mach_port_t mainPort = 0;
  132. struct statfs *mntbufp;
  133. int i, mounts;
  134. if (ioMainPort == NULL)
  135. {
  136. ioMainPort = (ioMainPortFn) dlsym(RTLD_DEFAULT, "IOMainPort");
  137. if (!ioMainPort)
  138. ioMainPort = (ioMainPortFn) dlsym(RTLD_DEFAULT, "IOMasterPort");
  139. if (!ioMainPort)
  140. return; /* oh well, no CD-ROMs for you. */
  141. } /* if */
  142. if (ioMainPort(MACH_PORT_NULL, &mainPort) != KERN_SUCCESS)
  143. BAIL(PHYSFS_ERR_OS_ERROR, ) /*return void*/;
  144. mounts = getmntinfo(&mntbufp, MNT_WAIT); /* NOT THREAD SAFE! */
  145. for (i = 0; i < mounts; i++)
  146. {
  147. char *dev = mntbufp[i].f_mntfromname;
  148. char *mnt = mntbufp[i].f_mntonname;
  149. if (strncmp(dev, devPrefix, prefixLen) != 0) /* a virtual device? */
  150. continue;
  151. dev += prefixLen;
  152. if (darwinIsMountedDisc(dev, mainPort))
  153. cb(data, mnt);
  154. } /* for */
  155. #endif /* !defined(PHYSFS_NO_CDROM_SUPPORT) */
  156. } /* __PHYSFS_platformDetectAvailableCDs */
  157. #endif /* PHYSFS_PLATFORM_APPLE */
  158. /* end of physfs_platform_apple.m ... */