move config-file seeking code to its own thing.

look also into the same directory as melonDS. make it the preferred place for storing melonDS.ini.
rewrite WinMain() wrapper.
This commit is contained in:
StapleButter 2018-12-11 21:34:05 +01:00
parent 9a0bf912d9
commit 40f3f91368
8 changed files with 256 additions and 143 deletions

View File

@ -23,6 +23,7 @@ SET(SOURCES
src/GPU2D.cpp
src/GPU3D.cpp
src/GPU3D_Soft.cpp
src/melon_fopen.cpp
src/NDS.cpp
src/NDSCart.cpp
src/RTC.cpp

View File

@ -234,6 +234,7 @@
<Unit filename="src/libui_sdl/libui/windows/winpublic.cpp" />
<Unit filename="src/libui_sdl/libui/windows/winutil.cpp" />
<Unit filename="src/libui_sdl/main.cpp" />
<Unit filename="src/melon_fopen.cpp" />
<Unit filename="src/melon_fopen.h" />
<Unit filename="src/pcap/bluetooth.h" />
<Unit filename="src/pcap/bpf.h" />

View File

@ -20,21 +20,17 @@
#include <string.h>
#include <stdlib.h>
#include "Config.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
#include "melon_fopen.h"
bool LocalFileExists(const char* name);
extern char* EmuDirectory;
namespace Config
{
const char* kConfigFile = "melonDS.ini";
int KeyMapping[12];
int JoyMapping[12];
@ -114,72 +110,6 @@ ConfigEntry ConfigFile[] =
{"", -1, NULL, 0, NULL, 0}
};
FILE* GetConfigFile(const char* fileName, const char* permissions)
{
// Locations are application directory, and XDG_CONFIG_HOME/melonds or AppData/MelonDS on windows
FILE* f;
// First check application directory
f = fopen(fileName, permissions);
if (f) return f;
#ifdef _WIN32
// Now check AppData
PWSTR appDataPath = NULL;
SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &appDataPath);
if (!appDataPath)
return NULL;
const WCHAR* appdir = L"\\melonDS\\";
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?
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);
// this will be more than enough
WCHAR fatperm[4];
fatperm[0] = permissions[0];
fatperm[1] = permissions[1];
fatperm[2] = permissions[2];
fatperm[3] = 0;
f = _wfopen(appDataPath, fatperm);
CoTaskMemFree(appDataPath);
delete[] wfileName;
if (f) return f;
#else
// 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;
#endif
return NULL;
}
bool HasConfigFile(const char* fileName)
{
FILE* f = GetConfigFile(fileName, "rb");
if (f)
{
fclose(f);
return true;
}
else
return false;
}
void Load()
{
@ -196,7 +126,7 @@ void Load()
entry++;
}
FILE* f = Config::GetConfigFile("melonDS.ini", "r");
FILE* f = melon_fopen_local(kConfigFile, "r");
if (!f) return;
char linebuf[1024];
@ -232,8 +162,26 @@ void Load()
void Save()
{
FILE* f = Config::GetConfigFile("melonDS.ini", "w");
if (!f) return;
FILE* f;
if (LocalFileExists(kConfigFile))
{
f = melon_fopen_local(kConfigFile, "w");
if (!f) return;
}
else
{
int dirlen = strlen(EmuDirectory);
int filelen = strlen(kConfigFile);
char* path = new char[dirlen + 1 + filelen + 1];
strncpy(&path[0], EmuDirectory, dirlen);
path[dirlen] = '/';
strncpy(&path[dirlen+1], kConfigFile, filelen);
path[dirlen+1+filelen] = '\0';
f = melon_fopen(path, "w");
delete[] path;
if (!f) return;
}
ConfigEntry* entry = &ConfigFile[0];
for (;;)

View File

@ -30,6 +30,7 @@
#include "RTC.h"
#include "Wifi.h"
#include "Platform.h"
#include "melon_fopen.h"
namespace NDS
@ -386,7 +387,7 @@ void Reset()
dbg_CyclesTimer7 = 0;
#endif // DEBUG_CHECK_DESYNC
f = Config::GetConfigFile("bios9.bin", "rb");
f = melon_fopen_local("bios9.bin", "rb");
if (!f)
{
printf("ARM9 BIOS not found\n");
@ -403,7 +404,7 @@ void Reset()
fclose(f);
}
f = Config::GetConfigFile("bios7.bin", "rb");
f = melon_fopen_local("bios7.bin", "rb");
if (!f)
{
printf("ARM7 BIOS not found\n");

View File

@ -22,6 +22,7 @@
#include "Config.h"
#include "NDS.h"
#include "SPI.h"
#include "melon_fopen.h"
namespace SPI_Firmware
@ -89,7 +90,7 @@ void Reset()
if (Firmware) delete[] Firmware;
Firmware = NULL;
FILE* f = Config::GetConfigFile("firmware.bin", "rb");
FILE* f = melon_fopen_local("firmware.bin", "rb");
if (!f)
{
printf("firmware.bin not found\n");
@ -129,7 +130,7 @@ void Reset()
// take a backup
char* firmbkp = "firmware.bin.bak";
f = Config::GetConfigFile(firmbkp, "rb");
f = melon_fopen_local(firmbkp, "rb");
if (f) fclose(f);
else
{
@ -324,7 +325,7 @@ void Write(u8 val, u32 hold)
if (!hold && (CurCmd == 0x02 || CurCmd == 0x0A))
{
FILE* f = Config::GetConfigFile("firmware.bin", "r+b");
FILE* f = melon_fopen_local("firmware.bin", "r+b");
if (f)
{
u32 cutoff = 0x7FA00 & FirmwareMask;

View File

@ -52,6 +52,9 @@ const int kScreenLayout[3] = {0, 1, 2};
const int kScreenSizing[4] = {0, 1, 2, 3};
char* EmuDirectory;
uiWindow* MainWindow;
uiArea* MainDrawArea;
@ -116,7 +119,7 @@ void GetSavestateName(int slot, char* filename, int len);
bool FileExists(char* name)
bool FileExists(const char* name)
{
FILE* f = melon_fopen(name, "rb");
if (!f) return false;
@ -124,6 +127,14 @@ bool FileExists(char* name)
return true;
}
bool LocalFileExists(const char* name)
{
FILE* f = melon_fopen_local(name, "rb");
if (!f) return false;
fclose(f);
return true;
}
void UpdateWindowTitle(void* data)
{
@ -1308,6 +1319,19 @@ int main(int argc, char** argv)
printf("melonDS " MELONDS_VERSION "\n");
printf(MELONDS_URL "\n");
{
int len = strlen(argv[0]);
while (len > 0)
{
if (argv[0][len] == '/') break;
if (argv[0][len] == '\\') break;
len--;
}
EmuDirectory = new char[len];
strncpy(EmuDirectory, argv[0], len);
EmuDirectory[len] = '\0';
}
// http://stackoverflow.com/questions/14543333/joystick-wont-work-using-sdl
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
@ -1335,7 +1359,7 @@ int main(int argc, char** argv)
Config::Load();
if (!Config::HasConfigFile("bios7.bin") || !Config::HasConfigFile("bios9.bin") || !Config::HasConfigFile("firmware.bin"))
if (!LocalFileExists("bios7.bin") || !LocalFileExists("bios9.bin") || !LocalFileExists("firmware.bin"))
{
uiMsgBoxError(
NULL,
@ -1618,6 +1642,7 @@ int main(int argc, char** argv)
uiUninit();
SDL_Quit();
delete[] EmuDirectory;
return 0;
}
@ -1627,41 +1652,26 @@ int main(int argc, char** argv)
int CALLBACK WinMain(HINSTANCE hinst, HINSTANCE hprev, LPSTR cmdline, int cmdshow)
{
char cmdargs[16][256];
int arg = 1;
int j = 0;
bool inquote = false;
int len = strlen(cmdline);
for (int i = 0; i < len; i++)
int argc = 0;
wchar_t** argv_w = CommandLineToArgvW(GetCommandLineW(), &argc);
char* nullarg = "";
char** argv = new char*[argc];
for (int i = 0; i < argc; i++)
{
char c = cmdline[i];
if (c == '\0') break;
if (c == '"') inquote = !inquote;
if (!inquote && c==' ')
{
if (j > 255) j = 255;
if (arg < 16) cmdargs[arg][j] = '\0';
arg++;
j = 0;
}
else
{
if (arg < 16 && j < 255) cmdargs[arg][j] = c;
j++;
}
int len = WideCharToMultiByte(CP_UTF8, 0, argv_w[i], -1, NULL, 0, NULL, NULL);
if (len < 1) return NULL;
argv[i] = new char[len];
int res = WideCharToMultiByte(CP_UTF8, 0, argv_w[i], -1, argv[i], len, NULL, NULL);
if (res != len) { delete[] argv[i]; argv[i] = nullarg; }
}
if (j > 255) j = 255;
if (arg < 16) cmdargs[arg][j] = '\0';
if (len > 0) arg++;
// FIXME!!
strncpy(cmdargs[0], "melonDS.exe", 256);
int ret = main(argc, argv);
char* cmdargptr[16];
for (int i = 0; i < 16; i++)
cmdargptr[i] = &cmdargs[i][0];
for (int i = 0; i < argc; i++) if (argv[i] != nullarg) delete[] argv[i];
delete[] argv;
return main(arg, cmdargptr);
return ret;
}
#endif

176
src/melon_fopen.cpp Normal file
View File

@ -0,0 +1,176 @@
/*
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/.
*/
#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* GetConfigFile(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

View File

@ -19,34 +19,9 @@
#ifndef MELON_FOPEN_H
#define MELON_FOPEN_H
#ifdef __WIN32__
#include <windows.h>
FILE* melon_fopen(const char* filename, const char* perm);
FILE* melon_fopen_local(const char* filename, const char* perm);
static 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;
}
#else
#define melon_fopen fopen
#endif
#endif // MELON_FOPEN_H