mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-07-21 05:09:46 -06:00

* cleaner code * faster in some cases * more accurate (on-demand compensation for timers and GPU) * less prone to desyncs * overall betterer
179 lines
4.8 KiB
C++
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
|