From c5a2fb1b02f1a0b563b8ac4ce8a52e65964bdfc2 Mon Sep 17 00:00:00 2001 From: GeorgH93 Date: Tue, 23 Mar 2021 02:24:55 +0100 Subject: [PATCH] Add PlatformFolders class --- openVulkanoCpp/IO/PlatformFolders.cpp | 119 ++++++++++++++++++++++++++ openVulkanoCpp/IO/PlatformFolders.hpp | 49 +++++++++++ 2 files changed, 168 insertions(+) create mode 100644 openVulkanoCpp/IO/PlatformFolders.cpp create mode 100644 openVulkanoCpp/IO/PlatformFolders.hpp diff --git a/openVulkanoCpp/IO/PlatformFolders.cpp b/openVulkanoCpp/IO/PlatformFolders.cpp new file mode 100644 index 0000000..1e39e9a --- /dev/null +++ b/openVulkanoCpp/IO/PlatformFolders.cpp @@ -0,0 +1,119 @@ +/* + * 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 + +#ifdef _WIN32 +#include +// For SHGetFolderPathW and various CSIDL "magic numbers" +#include +#include +#include + +namespace openVulkanoCpp +{ + 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 openVulkanoCpp +{ + 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 __APPLE__ + 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__ + dataHome = GetHome() + "/Documents/"; + configHome = dataHome; + stateDir = dataHome; + dataCache = GetHome() + "/Library/Caches/"; + tempDir = dataCache; +#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; + } +} diff --git a/openVulkanoCpp/IO/PlatformFolders.hpp b/openVulkanoCpp/IO/PlatformFolders.hpp new file mode 100644 index 0000000..938b3ac --- /dev/null +++ b/openVulkanoCpp/IO/PlatformFolders.hpp @@ -0,0 +1,49 @@ +/* + * 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/. + */ + +#pragma once + +#include + +namespace openVulkanoCpp +{ + class PlatformFolders + { + std::filesystem::path dataHome, configHome, stateDir, dataCache, tempDir; + std::filesystem::path desktop, documents, downloads, pictures, publicDir, music, video, savedGames; + + PlatformFolders(); + + static PlatformFolders& GetInstance(); + + public: + [[nodiscard]] static const std::filesystem::path& GetDataHomeDir() { return GetInstance().dataHome; } + + [[nodiscard]] static const std::filesystem::path& GetConfigHomeDir() { return GetInstance().configHome; } + + [[nodiscard]] static const std::filesystem::path& GetStateDir() { return GetInstance().stateDir; } + + [[nodiscard]] static const std::filesystem::path& GetCacheDir() { return GetInstance().dataCache; } + + [[nodiscard]] static const std::filesystem::path& GetTempDir() { return GetInstance().tempDir; } + + [[nodiscard]] static const std::filesystem::path& GetDesktopDir() { return GetInstance().desktop; } + + [[nodiscard]] static const std::filesystem::path& GetDocumentsDir() { return GetInstance().documents; } + + [[nodiscard]] static const std::filesystem::path& GetDownloadDir() { return GetInstance().downloads; } + + [[nodiscard]] static const std::filesystem::path& GetPicturesDir() { return GetInstance().pictures; } + + [[nodiscard]] static const std::filesystem::path& GetPublicShareDir() { return GetInstance().publicDir; } + + [[nodiscard]] static const std::filesystem::path& GetMusicDir() { return GetInstance().music; } + + [[nodiscard]] static const std::filesystem::path& GetVideoDir() { return GetInstance().video; } + + [[nodiscard]] static const std::filesystem::path& GetSaveGamesDir() { return GetInstance().savedGames; } + }; +}