platform_macosx.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. /*
  2. * Mac OS X 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_MACOSX
  11. #include <CoreFoundation/CoreFoundation.h>
  12. #if !defined(PHYSFS_NO_CDROM_SUPPORT)
  13. #include <Carbon/Carbon.h> /* !!! FIXME */
  14. #include <IOKit/storage/IOMedia.h>
  15. #include <IOKit/storage/IOCDMedia.h>
  16. #include <IOKit/storage/IODVDMedia.h>
  17. #include <sys/mount.h>
  18. #endif
  19. /* Seems to get defined in some system header... */
  20. #ifdef Free
  21. #undef Free
  22. #endif
  23. #include "physfs_internal.h"
  24. /* Wrap PHYSFS_Allocator in a CFAllocator... */
  25. static CFAllocatorRef cfallocator = NULL;
  26. static CFStringRef cfallocDesc(const void *info)
  27. {
  28. return CFStringCreateWithCString(cfallocator, "PhysicsFS",
  29. kCFStringEncodingASCII);
  30. } /* cfallocDesc */
  31. static void *cfallocMalloc(CFIndex allocSize, CFOptionFlags hint, void *info)
  32. {
  33. return allocator.Malloc(allocSize);
  34. } /* cfallocMalloc */
  35. static void cfallocFree(void *ptr, void *info)
  36. {
  37. allocator.Free(ptr);
  38. } /* cfallocFree */
  39. static void *cfallocRealloc(void *ptr, CFIndex newsize,
  40. CFOptionFlags hint, void *info)
  41. {
  42. if ((ptr == NULL) || (newsize <= 0))
  43. return NULL; /* ADC docs say you should always return NULL here. */
  44. return allocator.Realloc(ptr, newsize);
  45. } /* cfallocRealloc */
  46. int __PHYSFS_platformInit(void)
  47. {
  48. /* set up a CFAllocator, so Carbon can use the physfs allocator, too. */
  49. CFAllocatorContext ctx;
  50. memset(&ctx, '\0', sizeof (ctx));
  51. ctx.copyDescription = cfallocDesc;
  52. ctx.allocate = cfallocMalloc;
  53. ctx.reallocate = cfallocRealloc;
  54. ctx.deallocate = cfallocFree;
  55. cfallocator = CFAllocatorCreate(kCFAllocatorUseContext, &ctx);
  56. BAIL_IF_MACRO(!cfallocator, PHYSFS_ERR_OUT_OF_MEMORY, 0);
  57. return 1; /* success. */
  58. } /* __PHYSFS_platformInit */
  59. int __PHYSFS_platformDeinit(void)
  60. {
  61. CFRelease(cfallocator);
  62. cfallocator = NULL;
  63. return 1; /* always succeed. */
  64. } /* __PHYSFS_platformDeinit */
  65. /* CD-ROM detection code... */
  66. /*
  67. * Code based on sample from Apple Developer Connection:
  68. * http://developer.apple.com/samplecode/Sample_Code/Devices_and_Hardware/Disks/VolumeToBSDNode/VolumeToBSDNode.c.htm
  69. */
  70. #if !defined(PHYSFS_NO_CDROM_SUPPORT)
  71. static int darwinIsWholeMedia(io_service_t service)
  72. {
  73. int retval = 0;
  74. CFTypeRef wholeMedia;
  75. if (!IOObjectConformsTo(service, kIOMediaClass))
  76. return 0;
  77. wholeMedia = IORegistryEntryCreateCFProperty(service,
  78. CFSTR(kIOMediaWholeKey),
  79. cfallocator, 0);
  80. if (wholeMedia == NULL)
  81. return 0;
  82. retval = CFBooleanGetValue(wholeMedia);
  83. CFRelease(wholeMedia);
  84. return retval;
  85. } /* darwinIsWholeMedia */
  86. static int darwinIsMountedDisc(char *bsdName, mach_port_t masterPort)
  87. {
  88. int retval = 0;
  89. CFMutableDictionaryRef matchingDict;
  90. kern_return_t rc;
  91. io_iterator_t iter;
  92. io_service_t service;
  93. if ((matchingDict = IOBSDNameMatching(masterPort, 0, bsdName)) == NULL)
  94. return 0;
  95. rc = IOServiceGetMatchingServices(masterPort, matchingDict, &iter);
  96. if ((rc != KERN_SUCCESS) || (!iter))
  97. return 0;
  98. service = IOIteratorNext(iter);
  99. IOObjectRelease(iter);
  100. if (!service)
  101. return 0;
  102. rc = IORegistryEntryCreateIterator(service, kIOServicePlane,
  103. kIORegistryIterateRecursively | kIORegistryIterateParents, &iter);
  104. if (!iter)
  105. return 0;
  106. if (rc != KERN_SUCCESS)
  107. {
  108. IOObjectRelease(iter);
  109. return 0;
  110. } /* if */
  111. IOObjectRetain(service); /* add an extra object reference... */
  112. do
  113. {
  114. if (darwinIsWholeMedia(service))
  115. {
  116. if ( (IOObjectConformsTo(service, kIOCDMediaClass)) ||
  117. (IOObjectConformsTo(service, kIODVDMediaClass)) )
  118. {
  119. retval = 1;
  120. } /* if */
  121. } /* if */
  122. IOObjectRelease(service);
  123. } while ((service = IOIteratorNext(iter)) && (!retval));
  124. IOObjectRelease(iter);
  125. IOObjectRelease(service);
  126. return retval;
  127. } /* darwinIsMountedDisc */
  128. #endif /* !defined(PHYSFS_NO_CDROM_SUPPORT) */
  129. void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
  130. {
  131. #if !defined(PHYSFS_NO_CDROM_SUPPORT)
  132. const char *devPrefix = "/dev/";
  133. const int prefixLen = strlen(devPrefix);
  134. mach_port_t masterPort = 0;
  135. struct statfs *mntbufp;
  136. int i, mounts;
  137. if (IOMasterPort(MACH_PORT_NULL, &masterPort) != KERN_SUCCESS)
  138. BAIL_MACRO(PHYSFS_ERR_OS_ERROR, ) /*return void*/;
  139. mounts = getmntinfo(&mntbufp, MNT_WAIT); /* NOT THREAD SAFE! */
  140. for (i = 0; i < mounts; i++)
  141. {
  142. char *dev = mntbufp[i].f_mntfromname;
  143. char *mnt = mntbufp[i].f_mntonname;
  144. if (strncmp(dev, devPrefix, prefixLen) != 0) /* a virtual device? */
  145. continue;
  146. dev += prefixLen;
  147. if (darwinIsMountedDisc(dev, masterPort))
  148. cb(data, mnt);
  149. } /* for */
  150. #endif /* !defined(PHYSFS_NO_CDROM_SUPPORT) */
  151. } /* __PHYSFS_platformDetectAvailableCDs */
  152. static char *convertCFString(CFStringRef cfstr)
  153. {
  154. CFIndex len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
  155. kCFStringEncodingUTF8) + 1;
  156. char *retval = (char *) allocator.Malloc(len);
  157. BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
  158. if (CFStringGetCString(cfstr, retval, len, kCFStringEncodingUTF8))
  159. {
  160. /* shrink overallocated buffer if possible... */
  161. CFIndex newlen = strlen(retval) + 1;
  162. if (newlen < len)
  163. {
  164. void *ptr = allocator.Realloc(retval, newlen);
  165. if (ptr != NULL)
  166. retval = (char *) ptr;
  167. } /* if */
  168. } /* if */
  169. else /* probably shouldn't fail, but just in case... */
  170. {
  171. allocator.Free(retval);
  172. BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
  173. } /* else */
  174. return retval;
  175. } /* convertCFString */
  176. char *__PHYSFS_platformCalcBaseDir(const char *argv0)
  177. {
  178. CFURLRef cfurl = NULL;
  179. CFStringRef cfstr = NULL;
  180. CFMutableStringRef cfmutstr = NULL;
  181. char *retval = NULL;
  182. cfurl = CFBundleCopyBundleURL(CFBundleGetMainBundle());
  183. BAIL_IF_MACRO(cfurl == NULL, PHYSFS_ERR_OS_ERROR, NULL);
  184. cfstr = CFURLCopyFileSystemPath(cfurl, kCFURLPOSIXPathStyle);
  185. CFRelease(cfurl);
  186. BAIL_IF_MACRO(!cfstr, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
  187. cfmutstr = CFStringCreateMutableCopy(cfallocator, 0, cfstr);
  188. CFRelease(cfstr);
  189. BAIL_IF_MACRO(!cfmutstr, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
  190. CFStringAppendCString(cfmutstr, "/", kCFStringEncodingUTF8);
  191. retval = convertCFString(cfmutstr);
  192. CFRelease(cfmutstr);
  193. return retval; /* whew. */
  194. } /* __PHYSFS_platformCalcBaseDir */
  195. char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
  196. {
  197. /* !!! FIXME: there's a real API to determine this */
  198. const char *userdir = __PHYSFS_getUserDir();
  199. const char *append = "Library/Application Support/";
  200. const size_t len = strlen(userdir) + strlen(append) + strlen(app) + 2;
  201. char *retval = allocator.Malloc(len);
  202. BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
  203. snprintf(retval, len, "%s%s%s/", userdir, append, app);
  204. return retval;
  205. } /* __PHYSFS_platformCalcPrefDir */
  206. /* Platform allocator uses default CFAllocator at PHYSFS_init() time. */
  207. static CFAllocatorRef cfallocdef = NULL;
  208. static int macosxAllocatorInit(void)
  209. {
  210. int retval = 0;
  211. cfallocdef = CFAllocatorGetDefault();
  212. retval = (cfallocdef != NULL);
  213. if (retval)
  214. CFRetain(cfallocdef);
  215. return retval;
  216. } /* macosxAllocatorInit */
  217. static void macosxAllocatorDeinit(void)
  218. {
  219. if (cfallocdef != NULL)
  220. {
  221. CFRelease(cfallocdef);
  222. cfallocdef = NULL;
  223. } /* if */
  224. } /* macosxAllocatorDeinit */
  225. static void *macosxAllocatorMalloc(PHYSFS_uint64 s)
  226. {
  227. if (!__PHYSFS_ui64FitsAddressSpace(s))
  228. BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
  229. return CFAllocatorAllocate(cfallocdef, (CFIndex) s, 0);
  230. } /* macosxAllocatorMalloc */
  231. static void *macosxAllocatorRealloc(void *ptr, PHYSFS_uint64 s)
  232. {
  233. if (!__PHYSFS_ui64FitsAddressSpace(s))
  234. BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
  235. return CFAllocatorReallocate(cfallocdef, ptr, (CFIndex) s, 0);
  236. } /* macosxAllocatorRealloc */
  237. static void macosxAllocatorFree(void *ptr)
  238. {
  239. CFAllocatorDeallocate(cfallocdef, ptr);
  240. } /* macosxAllocatorFree */
  241. int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
  242. {
  243. allocator.Init = macosxAllocatorInit;
  244. allocator.Deinit = macosxAllocatorDeinit;
  245. allocator.Malloc = macosxAllocatorMalloc;
  246. allocator.Realloc = macosxAllocatorRealloc;
  247. allocator.Free = macosxAllocatorFree;
  248. return 1; /* return non-zero: we're supplying custom allocator. */
  249. } /* __PHYSFS_platformSetDefaultAllocator */
  250. #endif /* PHYSFS_PLATFORM_MACOSX */
  251. /* end of macosx.c ... */