File resources.cpp
File List > lib > utilities > resources.cpp
Go to the documentation of this file
#include "resources.hpp"
#include "assert/assert.hpp"
#include "printing/to_string.hpp"
#if defined(__WIN32__) || defined(_WIN32)
#include <winsock2.h>
// Don't reorder
#include <KnownFolders.h>
#include <shlobj.h>
#include <windows.h>
#endif
#ifdef __APPLE__
#include <mach-o/dyld.h>
#endif
#ifdef __linux__
#include <linux/limits.h>
#include <unistd.h>
#endif
fs::path get_asset_dir() {
#if defined(__WIN32__) || defined(_WIN32)
char buffer[MAX_PATH];
GetModuleFileNameA(NULL, buffer, MAX_PATH);
fs::path path(buffer);
#endif
#ifdef __APPLE__
char stack_buffer[4096];
uint32_t size = sizeof(stack_buffer);
std::vector<char> heap_buffer;
char* buf_ptr = stack_buffer;
if (_NSGetExecutablePath(buf_ptr, &size) != 0) {
heap_buffer.resize(size);
buf_ptr = heap_buffer.data();
if (_NSGetExecutablePath(buf_ptr, &size) != 0) {
Fail("Could not get executable path on macOS");
}
}
fs::path path(buf_ptr);
#endif
#ifdef __linux__
char buffer[PATH_MAX];
ssize_t len = readlink("/proc/self/exe", buffer, sizeof(buffer) - 1);
if (len != -1) {
buffer[len] = '\0';
}
fs::path path(buffer);
#endif
// First candidate, "<exe>/../../share/assets": on Linux/Windows the installed
// <prefix>/share/assets; on a macOS .app it resolves to
// MyApp.app/Contents/share/assets. The macOS packaging deliberately copies the
// assets THERE (scripts/macos-bundle-assets.sh) so the app is self-contained:
// a downloaded app runs under Gatekeeper App Translocation from a random temp
// dir with NO sibling share/, and only this in-bundle path survives. Do not
// remove it as "dead Linux code" — it is what keeps the GUI from aborting at
// launch on a clean Mac.
std::vector<fs::path> asset_paths = {path.parent_path().parent_path() / "share" / "assets"};
#ifdef __APPLE__
// Fallback for a non-translocated launch straight from the DMG/install tree:
// assets sitting next to the bundle at <prefix>/share/assets, four directory
// levels above the executable (MyApp.app/Contents/MacOS/<exe>).
asset_paths.push_back(path.parent_path().parent_path().parent_path().parent_path() / "share" /
"assets");
#endif
while (path.has_parent_path() && path.parent_path() != path) {
path = path.parent_path();
asset_paths.push_back(path / "assets");
}
for (fs::path asset_path : asset_paths) {
if (fs::exists(asset_path)) {
return asset_path;
}
}
Fail("Could not find asset directory. Tried " + to_string(asset_paths));
}
fs::path AssetRetriever::get_asset(const fs::path& asset) { return get_asset_dir() / asset; }
fs::path get_local_data_dir() {
#if defined(__WIN32__) || defined(_WIN32)
PWSTR path = nullptr;
HRESULT hr = SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &path);
if (SUCCEEDED(hr)) {
std::wstring ws(path);
CoTaskMemFree(path);
fs::path data_path = fs::path(std::string(ws.begin(), ws.end())) / "blaze";
fs::create_directories(data_path);
return data_path;
}
Fail("Could not get local windows data directory");
#endif
#ifdef __APPLE__
const char* home_dir = getenv("HOME");
if (home_dir == nullptr) {
Fail("Could not get local macOS data directory");
}
fs::path path = fs::path(home_dir) / "Library" / "Application Support" / "blaze";
fs::create_directories(path);
return path;
#endif
#ifdef __linux__
const char* home_dir = getenv("HOME");
if (home_dir == nullptr) {
Fail("Could not get local linux data directory");
}
fs::path path = fs::path(home_dir) / ".local" / "share" / "blaze";
fs::create_directories(path);
return path;
#endif
Fail("Unsupported platform for get_local_data_dir");
}
fs::path LocalDataRetriever::get_local_data(const fs::path& asset) {
return get_local_data_dir() / asset;
}