Files
OpenVulkano/openVulkanoCpp/IO/PlatformFolders.cpp
2025-02-09 18:30:32 +01:00

131 lines
4.3 KiB
C++

/*
* 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 <iostream>
#if __APPLE__
#include <TargetConditionals.h>
#endif
#ifdef _WIN32
#include <winerror.h>
// For SHGetFolderPathW and various CSIDL "magic numbers"
#include <shlobj.h>
#include <utf8.h>
#include <memory>
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<wchar_t, decltype(&CoTaskMemFree)> 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
if (const char* envValue = std::getenv(envName))
{
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 = home / "Library/Preferences";
stateDir = dataHome;
dataCache = home / "Library/Caches";
#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
#if TARGET_OS_IOS != 1
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;
}
}