From f08b87b41f0ffaabd7928d68c41d704e824b5de3 Mon Sep 17 00:00:00 2001
From: Arisotura <thetotalworm@gmail.com>
Date: Wed, 27 Mar 2019 13:34:26 +0100
Subject: * move melon_fopen_local() to Platform.cpp * make it require that the
 file already exist (hopefully fixing config saving bug) * finally axe
 melon_fopen.cpp

---
 src/libui_sdl/Platform.cpp | 162 ++++++++++++++++++++++++++++++++++++++++++++-
 src/libui_sdl/main.cpp     |  30 ++-------
 2 files changed, 166 insertions(+), 26 deletions(-)

(limited to 'src/libui_sdl')

diff --git a/src/libui_sdl/Platform.cpp b/src/libui_sdl/Platform.cpp
index a3619b5..3cf72bf 100644
--- a/src/libui_sdl/Platform.cpp
+++ b/src/libui_sdl/Platform.cpp
@@ -26,11 +26,17 @@
 #include "LAN_PCap.h"
 
 #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>
 	#include <winsock2.h>
 	#include <ws2tcpip.h>
 	#define socket_t    SOCKET
 	#define sockaddr_t  SOCKADDR
 #else
+    #include <glib.h>
 	#include <unistd.h>
 	#include <arpa/inet.h>
 	#include <netinet/in.h>
@@ -46,6 +52,8 @@
 #endif
 
 
+extern char* EmuDirectory;
+
 void Stop(bool internal);
 
 
@@ -81,8 +89,10 @@ void StopEmu()
 }
 
 
-FILE* OpenFile(const char* path, const char* mode)
+FILE* OpenFile(const char* path, const char* mode, bool mustexist)
 {
+    FILE* ret;
+
 #ifdef __WIN32__
 
     int len = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0);
@@ -98,13 +108,159 @@ FILE* OpenFile(const char* path, const char* mode)
     fatmode[2] = mode[2];
     fatmode[3] = 0;
 
-    FILE* ret = _wfopen(fatpath, fatmode);
+    if (mustexist)
+    {
+        ret = _wfopen(fatpath, L"rb");
+        if (ret) ret = _wfreopen(fatpath, fatmode, ret);
+    }
+    else
+        ret = _wfopen(fatpath, fatmode);
+
     delete[] fatpath;
+
+#else
+
+    if (mustexist)
+    {
+        ret = fopen(path, "rb");
+        if (ret) ret = freopen(path, mode);
+    }
+    else
+        ret = fopen(path, mode);
+
+#endif
+
     return ret;
+}
+
+FILE* OpenLocalFile(const char* path, const char* mode)
+{
+    bool relpath = false;
+    int pathlen = strlen(path);
+
+    if (pathlen >= 3)
+    {
+        if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || path[2] == '\\'))
+            relpath = true;
+    }
+
+#ifdef __WIN32__
+
+    if (pathlen > 3)
+    {
+        if (path[1] == ':' && path[2] == '\\')
+            return OpenFile(path, mode);
+    }
+
+    // Locations are application directory, and AppData/melonDS on windows
+
+    FILE* f;
+
+    // First check current working directory
+    f = OpenFile(path, mode, true);
+    if (f) return f;
+
+    // then emu directory
+    {
+        int dirlen = strlen(EmuDirectory);
+        if (dirlen)
+        {
+            int len = dirlen + 1 + pathlen + 1;
+            char* tmp = new char[len];
+            strncpy(&tmp[0], EmuDirectory, dirlen);
+            tmp[dirlen] = '\\';
+            strncpy(&tmp[dirlen+1], path, pathlen);
+            tmp[dirlen+1+pathlen] = '\0';
+
+            f = OpenFile(tmp, mode, true);
+            delete[] tmp;
+            if (f) return f;
+        }
+    }
+
+    // a path relative to AppData wouldn't make much sense
+    if (relpath) return NULL;
+
+    // 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] = mode[0];
+    fatperm[1] = mode[1];
+    fatperm[2] = mode[2];
+    fatperm[3] = 0;
+
+    int fnlen = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0);
+    if (fnlen < 1) return NULL;
+    WCHAR* wfileName = new WCHAR[fnlen];
+    int res = MultiByteToWideChar(CP_UTF8, 0, path, -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, L"rb");
+    if (f) f = _wfreopen(appDataPath, fatperm, f);
+    CoTaskMemFree(appDataPath);
+    delete[] wfileName;
+    if (f) return f;
+
+    return NULL;
 
 #else
 
-    return fopen(path, mode);
+    if (pathlen > 1)
+    {
+        if (path[0] == '/')
+            return OpenFile(path, mode);
+    }
+
+    // Locations are application directory, and XDG_CONFIG_HOME/melonds
+
+    FILE* f;
+
+    // First check current working directory
+    f = OpenFile(path, mode, true);
+    if (f) return f;
+
+    // then emu directory
+    {
+        int dirlen = strlen(EmuDirectory);
+        if (dirlen)
+        {
+            int len = dirlen + 1 + pathlen + 1;
+            char* tmp = new char[len];
+            strncpy(&tmp[0], EmuDirectory, dirlen);
+            tmp[dirlen] = '/';
+            strncpy(&tmp[dirlen+1], path, pathlen);
+            tmp[dirlen+1+pathlen] = '\0';
+
+            f = OpenFile(tmp, mode, true);
+            delete[] tmp;
+            if (f) return f;
+        }
+    }
+
+    if (relpath) return NULL;
+
+    // Now check XDG_CONFIG_HOME
+    // TODO: check for memory leak there
+    std::string fullpath = std::string(g_get_user_config_dir()) + "/melonds/" + path;
+    f = OpenFile(fullpath.c_str(), mode, true);
+    if (f) return f;
+
+    return NULL;
 
 #endif
 }
diff --git a/src/libui_sdl/main.cpp b/src/libui_sdl/main.cpp
index 4fc6679..566b346 100644
--- a/src/libui_sdl/main.cpp
+++ b/src/libui_sdl/main.cpp
@@ -25,7 +25,6 @@
 #include "libui/ui.h"
 
 #include "../types.h"
-#include "../melon_fopen.h"
 #include "../version.h"
 #include "PlatformConfig.h"
 
@@ -138,23 +137,6 @@ void GetSavestateName(int slot, char* filename, int len);
 
 
 
-bool FileExists(const char* name)
-{
-    FILE* f = Platform::OpenFile(name, "rb");
-    if (!f) return false;
-    fclose(f);
-    return true;
-}
-
-bool LocalFileExists(const char* name)
-{
-    FILE* f = melon_fopen_local(name, "rb");
-    if (!f) return false;
-    fclose(f);
-    return true;
-}
-
-
 void MicLoadWav(char* name)
 {
     SDL_AudioSpec format;
@@ -1077,8 +1059,8 @@ void Run()
     {
         char ssfile[1024];
         GetSavestateName(i+1, ssfile, 1024);
-        if (FileExists(ssfile)) uiMenuItemEnable(MenuItem_LoadStateSlot[i]);
-        else                    uiMenuItemDisable(MenuItem_LoadStateSlot[i]);
+        if (Platform::FileExists(ssfile)) uiMenuItemEnable(MenuItem_LoadStateSlot[i]);
+        else                              uiMenuItemDisable(MenuItem_LoadStateSlot[i]);
     }
 
     for (int i = 0; i < 9; i++) uiMenuItemEnable(MenuItem_SaveStateSlot[i]);
@@ -1210,7 +1192,7 @@ void LoadState(int slot)
         uiFreeText(file);
     }
 
-    if (!FileExists(filename))
+    if (!Platform::FileExists(filename))
     {
         EmuRunning = prevstatus;
         return;
@@ -1752,7 +1734,9 @@ int main(int argc, char** argv)
     if      (Config::AudioVolume < 0)   Config::AudioVolume = 0;
     else if (Config::AudioVolume > 256) Config::AudioVolume = 256;
 
-    if (!LocalFileExists("bios7.bin") || !LocalFileExists("bios9.bin") || !LocalFileExists("firmware.bin"))
+    if (!Platform::LocalFileExists("bios7.bin") ||
+        !Platform::LocalFileExists("bios9.bin") ||
+        !Platform::LocalFileExists("firmware.bin"))
     {
         uiMsgBoxError(
             NULL,
@@ -1770,7 +1754,7 @@ int main(int argc, char** argv)
     }
 
     {
-        FILE* f = melon_fopen_local("romlist.bin", "rb");
+        FILE* f = Platform::OpenLocalFile("romlist.bin", "rb");
         if (f)
         {
             u32 data;
-- 
cgit v1.2.3