27 const char* userprofile = std::getenv(
"USERPROFILE");
28 if (userprofile && *userprofile) {
29 return std::filesystem::path(userprofile);
33 const char* homedrive = std::getenv(
"HOMEDRIVE");
34 const char* homepath = std::getenv(
"HOMEPATH");
35 if (homedrive && homepath) {
36 return std::filesystem::path(std::string(homedrive) + std::string(homepath));
41 auto temp = std::filesystem::temp_directory_path(ec);
45 return std::filesystem::path(
".");
48 const char* home = std::getenv(
"HOME");
50 return std::filesystem::path(home);
54 struct passwd* pw = getpwuid(getuid());
55 if (pw && pw->pw_dir) {
56 return std::filesystem::path(pw->pw_dir);
61 auto cwd = std::filesystem::current_path(ec);
65 return std::filesystem::path(
".");
69 return std::filesystem::path(
".");
75 wchar_t path[MAX_PATH];
76 if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, path))) {
77 std::filesystem::path app_data = std::filesystem::path(path) /
"yaze";
86 std::filesystem::path app_data = home /
"yaze_data";
96 std::filesystem::path app_data = home /
".yaze";
185 const std::string& relative_path) {
186 std::vector<std::filesystem::path> search_paths;
190#ifdef YAZE_ASSETS_PATH
192 search_paths.push_back(std::filesystem::path(YAZE_ASSETS_PATH) / relative_path);
199 static std::filesystem::path cached_cwd;
200 static bool cwd_cached =
false;
204 cached_cwd = std::filesystem::current_path(ec);
208 if (!cached_cwd.empty()) {
210 search_paths.push_back(cached_cwd /
"assets" / relative_path);
217 static std::filesystem::path cached_exe_dir;
218 static bool exe_dir_cached =
false;
220 if (!exe_dir_cached) {
223 char exe_path[PATH_MAX];
224 uint32_t size =
sizeof(exe_path);
225 if (_NSGetExecutablePath(exe_path, &size) == 0) {
226 cached_exe_dir = std::filesystem::path(exe_path).parent_path();
228#elif defined(__linux__)
229 char exe_path[PATH_MAX];
230 ssize_t len = readlink(
"/proc/self/exe", exe_path,
sizeof(exe_path) - 1);
232 exe_path[len] =
'\0';
233 cached_exe_dir = std::filesystem::path(exe_path).parent_path();
236 wchar_t exe_path[MAX_PATH];
237 if (GetModuleFileNameW(NULL, exe_path, MAX_PATH) != 0) {
238 cached_exe_dir = std::filesystem::path(exe_path).parent_path();
244 exe_dir_cached =
true;
247 if (!cached_exe_dir.empty()) {
249 search_paths.push_back(cached_exe_dir /
"assets" / relative_path);
251 search_paths.push_back(cached_exe_dir.parent_path() /
"assets" / relative_path);
258 if (!cached_cwd.empty()) {
260 auto parent = cached_cwd.parent_path();
261 if (!parent.empty() && parent != cached_cwd) {
262 search_paths.push_back(parent /
"assets" / relative_path);
263 auto grandparent = parent.parent_path();
264 if (!grandparent.empty() && grandparent != parent) {
265 search_paths.push_back(grandparent /
"assets" / relative_path);
274 static std::filesystem::path cached_home;
275 static bool home_cached =
false;
286 if (!cached_home.empty() && cached_home !=
".") {
288 search_paths.push_back(cached_home /
".yaze" /
"assets" / relative_path);
297 search_paths.push_back(std::filesystem::path(
"/usr/local/share/yaze/assets") / relative_path);
298 search_paths.push_back(std::filesystem::path(
"/usr/share/yaze/assets") / relative_path);
306 const size_t max_paths_to_check = 20;
309 for (
const auto& candidate : search_paths) {
310 if (++checked > max_paths_to_check) {
316 std::error_code exists_ec;
317 if (std::filesystem::exists(candidate, exists_ec) && !exists_ec) {
319 auto status = std::filesystem::status(candidate, exists_ec);
320 if (!exists_ec && status.type() != std::filesystem::file_type::not_found) {
331 return absl::NotFoundError(
332 absl::StrCat(
"Asset not found: ", relative_path));
334 }
catch (
const std::exception& e) {
335 return absl::InternalError(
336 absl::StrCat(
"Exception while searching for asset: ", e.what()));
338 return absl::InternalError(
"Unknown exception while searching for asset");