diff options
Diffstat (limited to 'src/melon_fopen.cpp')
-rw-r--r-- | src/melon_fopen.cpp | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/src/melon_fopen.cpp b/src/melon_fopen.cpp new file mode 100644 index 0000000..04d3caf --- /dev/null +++ b/src/melon_fopen.cpp @@ -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* 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 |