/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include "PlatformFolders.hpp" #include #if __APPLE__ #include #endif #ifdef _WIN32 #include // For SHGetFolderPathW and various CSIDL "magic numbers" #include #include #include namespace OpenVulkano { namespace { std::string GetKnownWindowsFolder(REFKNOWNFOLDERID folderId, std::string name) { LPWSTR wszPath = NULL; HRESULT hr; hr = SHGetKnownFolderPath(folderId, KF_FLAG_CREATE, NULL, &wszPath); std::unique_ptr scopeBoundMemory(wszPath, &CoTaskMemFree); if (!SUCCEEDED(hr)) { throw std::runtime_error("Failed to find " + name + "folder."); } std::wstring winPath(wszPath); std::string str; utf8::utf16to8(winPath.begin(), winPath.end(), std::back_inserter(str)); return str; } } } #endif namespace OpenVulkano { namespace { std::filesystem::path GetHome() { auto home = std::getenv("HOME"); if (home == nullptr) throw std::runtime_error("HOME environment variable not set!"); return home; } [[nodiscard]] std::filesystem::path GetXDGFolderDefault(const char* envName, std::string_view defaultRelativePath) { #ifndef TARGET_OS_IOS != 1 const char* envValue = std::getenv(envName); if (envValue) { if (envValue[0] == '/') return envValue; std::cerr << "Ignoring environment '" << envName << "' (value: '" << envValue << "') because it's relative! XDG specifies it should be absolute path. Falling back to default path."; } #endif return GetHome() / defaultRelativePath; } } PlatformFolders::PlatformFolders() { #ifdef __APPLE__ #if TARGET_OS_IOS == 1 dataHome = GetHome() / "Documents/"; configHome = dataHome; stateDir = dataHome; dataCache = GetHome() / "Library/Caches/"; tempDir = dataCache; #else const auto home = GetHome(); dataHome = home / "Library/Application Support"; configHome = dataHome; stateDir = dataHome; dataCache = home / "Library/Caches"; tempDir = GetXDGFolderDefault("TMPDIR", "tmp"); #endif #elif defined(_WIN32) dataHome = GetKnownWindowsFolder(FOLDERID_RoamingAppData, "RoamingAppData"); configHome = GetKnownWindowsFolder(FOLDERID_RoamingAppData, "RoamingAppData"); stateDir = GetKnownWindowsFolder(FOLDERID_LocalAppData, "LocalAppData"); dataCache = GetKnownWindowsFolder(FOLDERID_LocalAppData, "LocalAppData"); desktop = GetKnownWindowsFolder(FOLDERID_Desktop, "Desktop"); documents = GetKnownWindowsFolder(FOLDERID_Documents, "Documents"); downloads = GetKnownWindowsFolder(FOLDERID_Downloads, "Downloads"); pictures = GetKnownWindowsFolder(FOLDERID_Pictures, "Pictures"); publicDir = GetKnownWindowsFolder(FOLDERID_Public, "Public"); music = GetKnownWindowsFolder(FOLDERID_Music, "Music"); video = GetKnownWindowsFolder(FOLDERID_Videos, "Videos"); savedGames = GetKnownWindowsFolder(FOLDERID_SavedGames, "Saved Games"); #else dataHome = GetXDGFolderDefault("XDG_DATA_HOME", ".local/share"); configHome = GetXDGFolderDefault("XDG_CONFIG_HOME", ".config"); stateDir = GetXDGFolderDefault("XDG_STATE_HOME", ".local/state"); dataCache = GetXDGFolderDefault("XDG_CACHE_HOME", ".cache"); #endif #ifndef __APPLE__ tempDir = std::filesystem::temp_directory_path(); #endif // Use XDG resolution on Linux and MacOS (will skip the env variable check on MacOS and just use the fallbacks, since they align with apple) #ifndef _WIN32 desktop = GetXDGFolderDefault("XDG_DESKTOP_DIR", "Desktop"); documents = GetXDGFolderDefault("XDG_DOCUMENTS_DIR", "Documents"); downloads = GetXDGFolderDefault("XDG_DOWNLOAD_DIR", "Downloads"); pictures = GetXDGFolderDefault("XDG_PICTURES_DIR", "Pictures"); publicDir = GetXDGFolderDefault("XDG_PUBLICSHARE_DIR", "Public"); music = GetXDGFolderDefault("XDG_MUSIC_DIR", "Music"); #ifdef __APPLE__ video = GetXDGFolderDefault("XDG_VIDEOS_DIR", "Movies"); #else video = GetXDGFolderDefault("XDG_VIDEOS_DIR", "Videos"); #endif savedGames = documents / "Saved Games"; #endif } PlatformFolders& PlatformFolders::GetInstance() { static PlatformFolders instance; return instance; } }