Files
melonDS/src/melon_fopen.cpp
StapleButter 669247e8c8 redesign main emu loop to use timestamps instead of being a trainwreck
* cleaner code
* faster in some cases
* more accurate (on-demand compensation for timers and GPU)
* less prone to desyncs
* overall betterer
2019-01-05 05:28:58 +01:00

179 lines
4.8 KiB
C++

/*
Copyright 2016-2019 StapleButter
This file is part of melonDS.
melonDS is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with melonDS. If not, see http://www.gnu.org/licenses/.
*/
// TODO: all this should ideally go in Platform.cpp
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <string>
#ifdef _WIN32
#define NTDDI_VERSION 0x06000000 // GROSS FUCKING HACK
#include <windows.h>
//#include <knownfolders.h> // FUCK THAT SHIT
extern "C" const GUID DECLSPEC_SELECTANY FOLDERID_RoamingAppData = {0x3eb685db, 0x65f9, 0x4cf6, {0xa0, 0x3a, 0xe3, 0xef, 0x65, 0x72, 0x9f, 0x3d}};
#include <shlobj.h>
#else
#include <glib.h>
#endif
extern char* EmuDirectory;
#ifdef __WIN32__
FILE* melon_fopen(const char* path, const char* mode)
{
int len = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0);
if (len < 1) return NULL;
WCHAR* fatass = new WCHAR[len];
int res = MultiByteToWideChar(CP_UTF8, 0, path, -1, fatass, len);
if (res != len) { delete[] fatass; return NULL; } // checkme?
// this will be more than enough
WCHAR fatmode[4];
fatmode[0] = mode[0];
fatmode[1] = mode[1];
fatmode[2] = mode[2];
fatmode[3] = 0;
FILE* ret = _wfopen(fatass, fatmode);
delete[] fatass;
return ret;
}
FILE* melon_fopen_local(const char* fileName, const char* permissions)
{
// Locations are application directory, and AppData/melonDS on windows
FILE* f;
// First check current working directory
f = fopen(fileName, permissions);
if (f) return f;
// then emu directory
{
int dirlen = strlen(EmuDirectory);
if (dirlen)
{
int filelen = strlen(fileName);
int len = dirlen + 1 + filelen + 1;
char* tmp = new char[len];
strncpy(&tmp[0], EmuDirectory, dirlen);
tmp[dirlen] = '\\';
strncpy(&tmp[dirlen+1], fileName, filelen);
tmp[dirlen+1+filelen] = '\0';
f = melon_fopen(tmp, permissions);
delete[] tmp;
if (f) return f;
}
}
// Now check AppData
PWSTR appDataPath = NULL;
SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &appDataPath);
if (!appDataPath)
return NULL;
// this will be more than enough
WCHAR fatperm[4];
fatperm[0] = permissions[0];
fatperm[1] = permissions[1];
fatperm[2] = permissions[2];
fatperm[3] = 0;
int fnlen = MultiByteToWideChar(CP_UTF8, 0, fileName, -1, NULL, 0);
if (fnlen < 1) return NULL;
WCHAR* wfileName = new WCHAR[fnlen];
int res = MultiByteToWideChar(CP_UTF8, 0, fileName, -1, wfileName, fnlen);
if (res != fnlen) { delete[] wfileName; return NULL; } // checkme?
const WCHAR* appdir = L"\\melonDS\\";
int pos = wcslen(appDataPath);
void* ptr = CoTaskMemRealloc(appDataPath, (pos+wcslen(appdir)+fnlen+1)*sizeof(WCHAR));
if (!ptr) { delete[] wfileName; return NULL; } // oh well
appDataPath = (PWSTR)ptr;
wcscpy(&appDataPath[pos], appdir); pos += wcslen(appdir);
wcscpy(&appDataPath[pos], wfileName);
f = _wfopen(appDataPath, fatperm);
CoTaskMemFree(appDataPath);
delete[] wfileName;
if (f) return f;
return NULL;
}
#else
FILE* melon_fopen(const char* filename, const char* perm) { return fopen(filename, perm); }
FILE* melon_fopen_local(const char* fileName, const char* permissions)
{
// Locations are application directory, and XDG_CONFIG_HOME/melonds
FILE* f;
// First check current working directory
f = fopen(fileName, permissions);
if (f) return f;
// then emu directory
{
int dirlen = strlen(EmuDirectory);
if (dirlen)
{
int filelen = strlen(fileName);
int len = dirlen + 1 + filelen + 1;
char* tmp = new char[len];
strncpy(&tmp[0], EmuDirectory, dirlen);
tmp[dirlen] = '/';
strncpy(&tmp[dirlen+1], fileName, filelen);
tmp[dirlen+1+filelen] = '\0';
f = fopen(tmp, permissions);
delete[] tmp;
if (f) return f;
}
}
// Now check XDG_CONFIG_HOME
// TODO: check for memory leak there
std::string path = std::string(g_get_user_config_dir()) + "/melonds/" + fileName;
f = fopen(path.c_str(), permissions);
if (f) return f;
return NULL;
}
#endif