Skip to content

Latest commit

 

History

History
365 lines (287 loc) · 10.3 KB

platform_macosx.c

File metadata and controls

365 lines (287 loc) · 10.3 KB
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
* 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>
Jul 10, 2011
Jul 10, 2011
19
#include <sys/stat.h>
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/* 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)
{
Mar 20, 2012
Mar 20, 2012
34
35
return CFStringCreateWithCString(cfallocator, "PhysicsFS",
kCFStringEncodingASCII);
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
} /* 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);
Mar 20, 2012
Mar 20, 2012
70
BAIL_IF_MACRO(!cfallocator, PHYSFS_ERR_OUT_OF_MEMORY, 0);
Jan 28, 2010
Jan 28, 2010
71
return 1; /* success. */
72
73
74
75
76
77
78
} /* __PHYSFS_platformInit */
int __PHYSFS_platformDeinit(void)
{
CFRelease(cfallocator);
cfallocator = NULL;
Jan 28, 2010
Jan 28, 2010
79
return 1; /* always succeed. */
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
} /* __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))
Jan 28, 2010
Jan 28, 2010
96
return 0;
97
98
99
100
101
wholeMedia = IORegistryEntryCreateCFProperty(service,
CFSTR(kIOMediaWholeKey),
cfallocator, 0);
if (wholeMedia == NULL)
Jan 28, 2010
Jan 28, 2010
102
return 0;
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
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)
Jan 28, 2010
Jan 28, 2010
120
return 0;
121
122
123
rc = IOServiceGetMatchingServices(masterPort, matchingDict, &iter);
if ((rc != KERN_SUCCESS) || (!iter))
Jan 28, 2010
Jan 28, 2010
124
return 0;
125
126
127
128
service = IOIteratorNext(iter);
IOObjectRelease(iter);
if (!service)
Jan 28, 2010
Jan 28, 2010
129
return 0;
130
131
132
133
134
rc = IORegistryEntryCreateIterator(service, kIOServicePlane,
kIORegistryIterateRecursively | kIORegistryIterateParents, &iter);
if (!iter)
Jan 28, 2010
Jan 28, 2010
135
return 0;
136
137
138
139
if (rc != KERN_SUCCESS)
{
IOObjectRelease(iter);
Jan 28, 2010
Jan 28, 2010
140
return 0;
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
} /* 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);
Jan 28, 2010
Jan 28, 2010
161
return retval;
162
163
164
165
166
167
168
169
170
171
172
173
} /* 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)
Mar 20, 2012
Mar 20, 2012
174
BAIL_MACRO(PHYSFS_ERR_OS_ERROR, ) /*return void*/;
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
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);
Mar 20, 2012
Mar 20, 2012
196
BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
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);
Mar 20, 2012
Mar 20, 2012
213
BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
Jan 28, 2010
Jan 28, 2010
216
return retval;
217
218
219
220
221
222
} /* convertCFString */
char *__PHYSFS_platformCalcBaseDir(const char *argv0)
{
ProcessSerialNumber psn = { 0, kCurrentProcess };
Jul 10, 2011
Jul 10, 2011
223
struct stat statbuf;
224
225
226
227
228
229
FSRef fsref;
CFRange cfrange;
CFURLRef cfurl = NULL;
CFStringRef cfstr = NULL;
CFMutableStringRef cfmutstr = NULL;
char *retval = NULL;
Jul 10, 2011
Jul 10, 2011
230
231
char *cstr = NULL;
int rc = 0;
Mar 20, 2012
Mar 20, 2012
233
234
if (GetProcessBundleLocation(&psn, &fsref) != noErr)
BAIL_MACRO(PHYSFS_ERR_OS_ERROR, NULL);
235
cfurl = CFURLCreateFromFSRef(cfallocator, &fsref);
Mar 20, 2012
Mar 20, 2012
236
BAIL_IF_MACRO(cfurl == NULL, PHYSFS_ERR_OS_ERROR, NULL);
237
238
cfstr = CFURLCopyFileSystemPath(cfurl, kCFURLPOSIXPathStyle);
CFRelease(cfurl);
Mar 20, 2012
Mar 20, 2012
239
BAIL_IF_MACRO(!cfstr, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
240
241
cfmutstr = CFStringCreateMutableCopy(cfallocator, 0, cfstr);
CFRelease(cfstr);
Mar 20, 2012
Mar 20, 2012
242
BAIL_IF_MACRO(!cfmutstr, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
Jul 10, 2011
Jul 10, 2011
244
245
246
/* we have to decide if we got a binary's path, or the .app dir... */
cstr = convertCFString(cfmutstr);
if (cstr == NULL)
247
248
{
CFRelease(cfmutstr);
Jan 28, 2010
Jan 28, 2010
249
return NULL;
Jul 10, 2011
Jul 10, 2011
252
253
254
255
256
257
258
rc = stat(cstr, &statbuf);
allocator.Free(cstr); /* done with this. */
if (rc == -1)
{
CFRelease(cfmutstr);
return NULL; /* maybe default behaviour will work? */
} /* if */
Jul 10, 2011
Jul 10, 2011
260
261
262
263
264
265
266
267
268
269
270
271
272
273
if (S_ISREG(statbuf.st_mode))
{
/* Find last dirsep so we can chop the 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);
Jul 10, 2011
Jul 10, 2011
275
276
277
278
279
280
281
282
283
/* 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. */
} /* if */
284
285
286
287
retval = convertCFString(cfmutstr);
CFRelease(cfmutstr);
Jan 28, 2010
Jan 28, 2010
288
return retval; /* whew. */
289
290
291
} /* __PHYSFS_platformCalcBaseDir */
Mar 22, 2012
Mar 22, 2012
292
293
294
295
296
297
298
299
300
301
302
303
304
char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
{
/* !!! FIXME: there's a real API to determine this */
const char *userdir = __PHYSFS_getUserDir();
const char *append = "Library/Application Support/";
const size_t len = strlen(userdir) + strlen(append) + strlen(app) + 1;
char *retval = allocator.Malloc(len);
BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
snprintf(retval, len, "%s%s%s", userdir, append, app);
return retval;
} /* __PHYSFS_platformCalcPrefDir */
305
306
307
308
309
310
311
312
313
314
315
/* 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);
Jan 28, 2010
Jan 28, 2010
316
return retval;
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
} /* macosxAllocatorInit */
static void macosxAllocatorDeinit(void)
{
if (cfallocdef != NULL)
{
CFRelease(cfallocdef);
cfallocdef = NULL;
} /* if */
} /* macosxAllocatorDeinit */
static void *macosxAllocatorMalloc(PHYSFS_uint64 s)
{
Mar 20, 2012
Mar 20, 2012
332
333
if (!__PHYSFS_ui64FitsAddressSpace(s))
BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
Jan 28, 2010
Jan 28, 2010
334
return CFAllocatorAllocate(cfallocdef, (CFIndex) s, 0);
335
336
337
338
339
} /* macosxAllocatorMalloc */
static void *macosxAllocatorRealloc(void *ptr, PHYSFS_uint64 s)
{
Mar 20, 2012
Mar 20, 2012
340
341
if (!__PHYSFS_ui64FitsAddressSpace(s))
BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
Jan 28, 2010
Jan 28, 2010
342
return CFAllocatorReallocate(cfallocdef, ptr, (CFIndex) s, 0);
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
} /* 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;
Jan 28, 2010
Jan 28, 2010
359
return 1; /* return non-zero: we're supplying custom allocator. */
360
361
362
363
364
} /* __PHYSFS_platformSetDefaultAllocator */
#endif /* PHYSFS_PLATFORM_MACOSX */
/* end of macosx.c ... */