snes9x/macosx/mac-file.cpp

620 lines
15 KiB
C++

/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
This file is licensed under the Snes9x License.
For further information, consult the LICENSE file in the root directory.
\*****************************************************************************/
/***********************************************************************************
SNES9X for Mac OS (c) Copyright John Stiles
Snes9x for Mac OS X
(c) Copyright 2001 - 2011 zones
(c) Copyright 2002 - 2005 107
(c) Copyright 2002 PB1400c
(c) Copyright 2004 Alexander and Sander
(c) Copyright 2004 - 2005 Steven Seeger
(c) Copyright 2005 Ryan Vogt
***********************************************************************************/
#include "snes9x.h"
#include "memmap.h"
#include "movie.h"
#include "display.h"
#include <libgen.h>
#include "mac-prefix.h"
#include "mac-dialog.h"
#include "mac-os.h"
#include "mac-stringtools.h"
#include "mac-file.h"
static void AddFolderIcon (FSRef *, const char *);
static OSStatus FindSNESFolder (FSRef *, char *, const char *);
static OSStatus FindApplicationSupportFolder (FSRef *, char *, const char *);
static OSStatus FindCustomFolder (FSRef *, char *, const char *);
void CheckSaveFolder (FSRef *cartRef)
{
OSStatus err;
Boolean r;
FSCatalogInfo finfo;
FSVolumeInfo vinfo;
FSRef ref;
CFURLRef burl, purl;
char s[PATH_MAX + 1];
switch (saveInROMFolder)
{
case 0: // Snes9x folder
burl = CFBundleCopyBundleURL(CFBundleGetMainBundle());
purl = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, burl);
r = CFURLGetFSRef(purl, &ref);
CFRelease(purl);
CFRelease(burl);
break;
case 1: // ROM folder
err = FSGetCatalogInfo(cartRef, kFSCatInfoNone, NULL, NULL, NULL, &ref);
break;
case 2: // Application Support folder
return;
case 4: // Custom folder
if (saveFolderPath == NULL)
{
saveInROMFolder = 2;
return;
}
r = CFStringGetCString(saveFolderPath, s, PATH_MAX, kCFStringEncodingUTF8);
err = FSPathMakeRef((unsigned char *) s, &ref, NULL);
if (err)
{
AppearanceAlert(kAlertCautionAlert, kS9xMacAlertFolderNotFound, kS9xMacAlertFolderNotFoundHint);
saveInROMFolder = 2;
return;
}
break;
}
err = FSGetCatalogInfo(&ref, kFSCatInfoUserPrivs | kFSCatInfoVolume, &finfo, NULL, NULL, NULL);
if (err == noErr)
{
if (finfo.userPrivileges & kioACUserNoMakeChangesMask)
{
AppearanceAlert(kAlertCautionAlert, kS9xMacAlertFolderFailToCreate, kS9xMacAlertFolderFailToCreateHint);
saveInROMFolder = 2;
return;
}
err = FSGetVolumeInfo(finfo.volume, 0, NULL, kFSVolInfoFlags, &vinfo, NULL, NULL);
if (err == noErr)
{
if ((vinfo.flags & kFSVolFlagHardwareLockedMask) || (vinfo.flags & kFSVolFlagSoftwareLockedMask))
{
AppearanceAlert(kAlertCautionAlert, kS9xMacAlertFolderFailToCreate, kS9xMacAlertFolderFailToCreateHint);
saveInROMFolder = 2;
return;
}
}
}
if (err)
saveInROMFolder = 2;
}
static OSStatus FindSNESFolder (FSRef *folderRef, char *folderPath, const char *folderName)
{
OSStatus err;
CFURLRef burl, purl;
CFStringRef fstr;
FSRef pref;
UniChar buffer[PATH_MAX + 1];
Boolean r;
fstr = CFStringCreateWithCString(kCFAllocatorDefault, folderName, CFStringGetSystemEncoding());
CFStringGetCharacters(fstr, CFRangeMake(0, CFStringGetLength(fstr)), buffer);
burl = CFBundleCopyBundleURL(CFBundleGetMainBundle());
purl = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, burl);
r = CFURLGetFSRef(purl, &pref);
err = FSMakeFSRefUnicode(&pref, CFStringGetLength(fstr), buffer, kTextEncodingUnicodeDefault, folderRef);
if (err == dirNFErr || err == fnfErr)
{
err = FSCreateDirectoryUnicode(&pref, CFStringGetLength(fstr), buffer, kFSCatInfoNone, NULL, folderRef, NULL, NULL);
if (err == noErr)
AddFolderIcon(folderRef, folderName);
}
if (err == noErr)
err = FSRefMakePath(folderRef, (unsigned char *) folderPath, PATH_MAX);
CFRelease(purl);
CFRelease(burl);
CFRelease(fstr);
return (err);
}
static OSStatus FindApplicationSupportFolder (FSRef *folderRef, char *folderPath, const char *folderName)
{
OSStatus err;
FSRef p2ref, p1ref;
CFStringRef fstr;
UniChar buffer[PATH_MAX + 1];
UniChar s9xfolder[6] = { 'S', 'n', 'e', 's', '9', 'x' },
oldfolder[6] = { 'S', 'N', 'E', 'S', '9', 'X' };
err = FSFindFolder(kUserDomain, kApplicationSupportFolderType, kCreateFolder, &p2ref);
if (err)
return (err);
err = FSMakeFSRefUnicode(&p2ref, 6, s9xfolder, kTextEncodingUnicodeDefault, &p1ref);
if (err == dirNFErr || err == fnfErr)
{
err = FSMakeFSRefUnicode(&p2ref, 6, oldfolder, kTextEncodingUnicodeDefault, &p1ref);
if (err == dirNFErr || err == fnfErr)
err = FSCreateDirectoryUnicode(&p2ref, 6, s9xfolder, kFSCatInfoNone, NULL, &p1ref, NULL, NULL);
}
if (err)
return (err);
fstr = CFStringCreateWithCString(kCFAllocatorDefault, folderName, CFStringGetSystemEncoding());
CFStringGetCharacters(fstr, CFRangeMake(0, CFStringGetLength(fstr)), buffer);
err = FSMakeFSRefUnicode(&p1ref, CFStringGetLength(fstr), buffer, kTextEncodingUnicodeDefault, folderRef);
if (err == dirNFErr || err == fnfErr)
{
err = FSCreateDirectoryUnicode(&p1ref, CFStringGetLength(fstr), buffer, kFSCatInfoNone, NULL, folderRef, NULL, NULL);
if (err == noErr)
AddFolderIcon(folderRef, folderName);
}
if (err == noErr)
err = FSRefMakePath(folderRef, (unsigned char *) folderPath, PATH_MAX);
CFRelease(fstr);
return (err);
}
static OSStatus FindCustomFolder (FSRef *folderRef, char *folderPath, const char *folderName)
{
OSStatus err;
CFStringRef fstr;
FSRef pref;
UniChar buffer[PATH_MAX + 1];
char s[PATH_MAX + 1];
if (saveFolderPath == NULL)
return (-1);
err = CFStringGetCString(saveFolderPath, s, PATH_MAX, kCFStringEncodingUTF8) ? noErr : -1;
if (err == noErr)
err = FSPathMakeRef((unsigned char *) s, &pref, NULL);
if (err)
return (err);
fstr = CFStringCreateWithCString(kCFAllocatorDefault, folderName, CFStringGetSystemEncoding());
CFStringGetCharacters(fstr, CFRangeMake(0, CFStringGetLength(fstr)), buffer);
err = FSMakeFSRefUnicode(&pref, CFStringGetLength(fstr), buffer, kTextEncodingUnicodeDefault, folderRef);
if (err == dirNFErr || err == fnfErr)
{
err = FSCreateDirectoryUnicode(&pref, CFStringGetLength(fstr), buffer, kFSCatInfoNone, NULL, folderRef, NULL, NULL);
if (err == noErr)
AddFolderIcon(folderRef, folderName);
}
if (err == noErr)
err = FSRefMakePath(folderRef, (unsigned char *) folderPath, PATH_MAX);
CFRelease(fstr);
return (err);
}
void ChangeTypeAndCreator (const char *path, OSType type, OSType creator)
{
OSStatus err;
FSRef ref;
err = FSPathMakeRef((unsigned char *) path, &ref, NULL);
if (err == noErr)
{
FSCatalogInfo catinfo;
err = FSGetCatalogInfo(&ref, kFSCatInfoFinderInfo, &catinfo, NULL, NULL, NULL);
if (err == noErr)
{
((FileInfo *) &catinfo.finderInfo)->fileCreator = creator;
((FileInfo *) &catinfo.finderInfo)->fileType = type;
err = FSSetCatalogInfo(&ref, kFSCatInfoFinderInfo, &catinfo);
}
}
}
static void AddFolderIcon (FSRef *fref, const char *folderName)
{
OSStatus err;
FSCatalogInfo fcat, icat;
FSRef bref, iref;
CFStringRef str;
CFURLRef url;
IconFamilyHandle family;
IconRef icon;
HFSUniStr255 fork;
Boolean r;
SInt16 resf;
char name[64];
UniChar iconName[5] = { 'I', 'c', 'o', 'n', '\r' };
strcpy(name, "folder_");
strcat(name, folderName);
str = CFStringCreateWithCString(kCFAllocatorDefault, name, CFStringGetSystemEncoding());
if (str)
{
url = CFBundleCopyResourceURL(CFBundleGetMainBundle(), str, CFSTR("icns"), NULL);
if (url)
{
r = CFURLGetFSRef(url, &bref);
if (r)
{
err = RegisterIconRefFromFSRef('~9X~', 'TEMP', &bref, &icon);
if (err == noErr)
{
err = FSGetResourceForkName(&fork);
if (err == noErr)
{
err = FSCreateResourceFile(fref, 5, iconName, kFSCatInfoNone, NULL, fork.length, fork.unicode, &iref, NULL);
if (err == noErr)
{
err = FSOpenResourceFile(&iref, fork.length, fork.unicode, fsWrPerm, &resf);
if (err == noErr)
{
err = IconRefToIconFamily(icon, kSelectorAllAvailableData, &family);
if (err == noErr)
{
AddResource((Handle) family, 'icns', -16455, "\p");
WriteResource((Handle) family);
ReleaseResource((Handle) family);
err = FSGetCatalogInfo(&iref, kFSCatInfoFinderInfo, &icat, NULL, NULL, NULL);
((FileInfo *) &icat.finderInfo)->finderFlags |= kIsInvisible;
((FileInfo *) &icat.finderInfo)->fileCreator = 'MACS';
((FileInfo *) &icat.finderInfo)->fileType = 'icon';
err = FSSetCatalogInfo(&iref, kFSCatInfoFinderInfo, &icat);
err = FSGetCatalogInfo(fref, kFSCatInfoFinderInfo, &fcat, NULL, NULL, NULL);
((FolderInfo *) &fcat.finderInfo)->finderFlags |= kHasCustomIcon;
((FolderInfo *) &fcat.finderInfo)->finderFlags &= ~kHasBeenInited;
err = FSSetCatalogInfo(fref, kFSCatInfoFinderInfo, &fcat);
}
CloseResFile(resf);
}
}
}
err = UnregisterIconRef('~9X~', 'TEMP');
}
}
CFRelease(url);
}
CFRelease(str);
}
}
const char * S9xGetFilename (const char *inExt, enum s9x_getdirtype dirtype)
{
static int index = 0;
static char filePath[4][PATH_MAX + 1];
OSStatus err;
FSRef ref;
uint32 type;
char folderName[16];
char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], fname[_MAX_FNAME + 1], ext[_MAX_EXT + 1];
const char *p;
index++;
if (index > 3)
index = 0;
folderName[0] = filePath[index][0] = 0;
if (strlen(inExt) < 4)
return (filePath[index]);
p = inExt + strlen(inExt) - 4;
type = ((uint32) p[0] << 24) + ((uint32) p[1] << 16) + ((uint32) p[2] << 8) + (uint32) p[3];
switch (type)
{
case '.srm':
case '.rtc':
strcpy(folderName, "SRAMs");
break;
case '.frz':
strcpy(folderName, "Freezes");
break;
case '.spc':
strcpy(folderName, "SPCs");
break;
case '.cht':
strcpy(folderName, "Cheats");
break;
case '.ups':
case '.ips':
strcpy(folderName, "Patches");
break;
case '.png':
strcpy(folderName, "Screenshots");
break;
case '.dat':
case '.out':
case '.log':
strcpy(folderName, "Logs");
break;
case '.bio': // dummy
strcpy(folderName, "BIOSes");
break;
}
if (folderName[0] && (saveInROMFolder != 1))
{
char s[PATH_MAX + 1];
s[0] = 0;
err = -1;
if (saveInROMFolder == 0)
{
err = FindSNESFolder(&ref, s, folderName);
if (err)
saveInROMFolder = 2;
}
if (saveInROMFolder == 4)
{
err = FindCustomFolder(&ref, s, folderName);
if (err)
saveInROMFolder = 2;
}
if (saveInROMFolder == 2)
err = FindApplicationSupportFolder(&ref, s, folderName);
if (err == noErr)
{
_splitpath(Memory.ROMFilename, drive, dir, fname, ext);
snprintf(filePath[index], PATH_MAX + 1, "%s%s%s%s", s, MAC_PATH_SEPARATOR, fname, inExt);
}
else
{
_splitpath(Memory.ROMFilename, drive, dir, fname, ext);
_makepath(filePath[index], drive, dir, fname, inExt);
}
}
else
{
_splitpath(Memory.ROMFilename, drive, dir, fname, ext);
_makepath(filePath[index], drive, dir, fname, inExt);
}
return (filePath[index]);
}
const char * S9xGetSPCFilename (void)
{
char spcExt[16];
sprintf(spcExt, ".%03d.spc", (int) spcFileCount);
spcFileCount++;
if (spcFileCount == 1000)
spcFileCount = 0;
return (S9xGetFilename(spcExt, SPC_DIR));
}
const char * S9xGetPNGFilename (void)
{
char pngExt[16];
sprintf(pngExt, ".%03d.png", (int) pngFileCount);
pngFileCount++;
if (pngFileCount == 1000)
pngFileCount = 0;
return (S9xGetFilename(pngExt, SCREENSHOT_DIR));
}
const char * S9xGetFreezeFilename (int which)
{
char frzExt[16];
sprintf(frzExt, ".%03d.frz", which);
return (S9xGetFilename(frzExt, SNAPSHOT_DIR));
}
const char * S9xGetFilenameInc (const char *inExt, enum s9x_getdirtype dirtype)
{
uint32 type;
const char *p;
if (strlen(inExt) < 4)
return (NULL);
p = inExt + strlen(inExt) - 4;
type = ((uint32) p[0] << 24) + ((uint32) p[1] << 16) + ((uint32) p[2] << 8) + (uint32) p[3];
switch (type)
{
case '.spc':
return (S9xGetSPCFilename());
case '.png':
return (S9xGetPNGFilename());
}
return (NULL);
}
const char * S9xChooseFilename (bool8 read_only)
{
return (NULL);
}
const char * S9xChooseMovieFilename (bool8 read_only)
{
return (NULL);
}
bool8 S9xOpenSnapshotFile (const char *fname, bool8 read_only, STREAM *file)
{
if (read_only)
{
if (0 != (*file = OPEN_STREAM(fname, "rb")))
return (true);
}
else
{
if (0 != (*file = OPEN_STREAM(fname, "wb")))
return (true);
}
return (false);
}
void S9xCloseSnapshotFile (STREAM file)
{
CLOSE_STREAM(file);
}
const char * S9xBasename (const char *in)
{
static char s[PATH_MAX + 1];
strncpy(s, in, PATH_MAX + 1);
s[PATH_MAX] = 0;
size_t l = strlen(s);
for (unsigned int i = 0; i < l; i++)
{
if (s[i] < 32 || s[i] >= 127)
s[i] = '_';
}
return (basename(s));
}
const char * S9xGetDirectory (enum s9x_getdirtype dirtype)
{
static int index = 0;
static char path[4][PATH_MAX + 1];
char inExt[16];
char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], fname[_MAX_FNAME + 1], ext[_MAX_EXT + 1];
index++;
if (index > 3)
index = 0;
switch (dirtype)
{
case SNAPSHOT_DIR: strcpy(inExt, ".frz"); break;
case SRAM_DIR: strcpy(inExt, ".srm"); break;
case SCREENSHOT_DIR: strcpy(inExt, ".png"); break;
case SPC_DIR: strcpy(inExt, ".spc"); break;
case CHEAT_DIR: strcpy(inExt, ".cht"); break;
case BIOS_DIR: strcpy(inExt, ".bio"); break;
case LOG_DIR: strcpy(inExt, ".log"); break;
default: strcpy(inExt, ".xxx"); break;
}
_splitpath(S9xGetFilename(inExt, dirtype), drive, dir, fname, ext);
_makepath(path[index], drive, dir, "", "");
int l = strlen(path[index]);
if (l > 1)
path[index][l - 1] = 0;
return (path[index]);
}
void _splitpath (const char *path, char *drive, char *dir, char *fname, char *ext)
{
drive[0] = 0;
fname[0] = 0;
ext[0] = 0;
dir[0] = 0;
int x;
x = strlen(path) - 1;
if (x < 0)
return;
while (x && (path[x] != MAC_PATH_SEP_CHAR))
x--;
if (x)
{
strcpy(dir, path);
dir[x + 1] = 0;
strcpy(fname, path + x + 1);
}
else
strcpy(fname, path);
x = strlen(fname);
while (x && (fname[x] != '.'))
x--;
if (x)
{
strcpy(ext, fname + x);
fname[x] = 0;
}
}
void _makepath (char *path, const char *drive, const char *dir, const char *fname, const char *ext)
{
static const char emp[] = "", dot[] = ".";
const char *d, *f, *e, *p;
d = dir ? dir : emp;
f = fname ? fname : emp;
e = ext ? ext : emp;
p = (e[0] && e[0] != '.') ? dot : emp;
snprintf(path, PATH_MAX + 1, "%s%s%s%s", d, f, p, e);
}