/* Copyright 2016-2019 Arisotura 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 #include #include #include #ifdef _WIN32 #define NTDDI_VERSION 0x06000000 // GROSS FUCKING HACK #include //#include // FUCK THAT SHIT extern "C" const GUID DECLSPEC_SELECTANY FOLDERID_RoamingAppData = {0x3eb685db, 0x65f9, 0x4cf6, {0xa0, 0x3a, 0xe3, 0xef, 0x65, 0x72, 0x9f, 0x3d}}; #include #else #include #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