35 const char* userprofile = std::getenv(
"USERPROFILE");
36 if (userprofile && *userprofile) {
37 return std::filesystem::path(userprofile);
41 const char* homedrive = std::getenv(
"HOMEDRIVE");
42 const char* homepath = std::getenv(
"HOMEPATH");
43 if (homedrive && homepath) {
44 return std::filesystem::path(std::string(homedrive) +
45 std::string(homepath));
50 auto temp = std::filesystem::temp_directory_path(ec);
54 return std::filesystem::path(
".");
55#elif defined(__EMSCRIPTEN__)
57 return std::filesystem::path(
"/home/web_user");
60 const char* home = std::getenv(
"HOME");
62 return std::filesystem::path(home);
66 struct passwd* pw = getpwuid(getuid());
67 if (pw && pw->pw_dir) {
68 return std::filesystem::path(pw->pw_dir);
73 auto cwd = std::filesystem::current_path(ec);
77 return std::filesystem::path(
".");
81 return std::filesystem::path(
".");
86#if defined(YAZE_IOS) || defined(YAZE_APPLE_MOBILE)
88 if (home.empty() || home ==
".") {
90 auto temp = std::filesystem::temp_directory_path(ec);
96 std::filesystem::path app_data =
97 home /
"Library" /
"Application Support" /
".yaze";
100 app_data = home /
"Documents" /
".yaze";
107#elif defined(__EMSCRIPTEN__)
119 std::filesystem::path app_data(
"/.yaze");
123 std::filesystem::path preferred;
124 if (!home.empty() && home !=
".") {
125 preferred = home /
".yaze";
128 std::vector<std::filesystem::path> legacy_paths;
129 auto add_legacy_path = [&](
const std::filesystem::path& path) {
133 if (std::find(legacy_paths.begin(), legacy_paths.end(), path) ==
134 legacy_paths.end()) {
135 legacy_paths.push_back(path);
140 wchar_t path[MAX_PATH];
141 if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, path))) {
142 add_legacy_path(std::filesystem::path(path) /
"yaze");
144 if (
const char* appdata = std::getenv(
"APPDATA")) {
146 add_legacy_path(std::filesystem::path(appdata) /
"yaze");
149#elif defined(__APPLE__)
150 if (!home.empty() && home !=
".") {
151 add_legacy_path(home /
"Library" /
"Application Support" /
"yaze");
152 add_legacy_path(home /
"Library" /
"Application Support" /
"Yaze");
155 if (!home.empty() && home !=
".") {
156 add_legacy_path(home /
".config" /
"yaze");
160 auto try_migrate = [&](
const std::filesystem::path& legacy) -> absl::Status {
161 if (legacy.empty() || preferred.empty()) {
162 return absl::OkStatus();
165 return absl::OkStatus();
169 std::filesystem::rename(legacy, preferred, ec);
171 return absl::OkStatus();
174 std::filesystem::create_directories(preferred, ec);
176 return absl::InternalError(
177 absl::StrCat(
"Failed to create .yaze directory: ", ec.message()));
180 std::filesystem::copy(legacy, preferred,
181 std::filesystem::copy_options::recursive |
182 std::filesystem::copy_options::skip_existing,
185 return absl::InternalError(
186 absl::StrCat(
"Failed to migrate legacy data: ", ec.message()));
192 std::filesystem::remove_all(legacy, ec);
195 return absl::OkStatus();
198 if (!preferred.empty()) {
200 for (
const auto& legacy : legacy_paths) {
202 (void)try_migrate(legacy);
214 for (
const auto& legacy : legacy_paths) {
221 if (preferred.empty()) {
222 std::filesystem::path fallback = std::filesystem::current_path() /
".yaze";
230 return absl::InternalError(
"Failed to resolve app data directory");
250#if defined(YAZE_IOS) || defined(YAZE_APPLE_MOBILE)
252 std::filesystem::path docs_dir = home /
"Documents" /
"Yaze";
255 docs_dir = home /
"Yaze";
263 wchar_t path[MAX_PATH];
264 if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, 0, path))) {
265 std::filesystem::path docs_dir = std::filesystem::path(path) /
"Yaze";
274 std::filesystem::path docs_dir = home /
"Documents" /
"Yaze";
280#elif defined(__EMSCRIPTEN__)
282 std::filesystem::path docs_dir(
"/.yaze/projects");
287 std::filesystem::path docs_dir = home /
"Documents" /
"Yaze";
291 docs_dir = home /
"Yaze";
395 const std::string& relative_path) {
396 std::vector<std::filesystem::path> search_paths;
400#ifdef YAZE_ASSETS_PATH
402 search_paths.push_back(std::filesystem::path(YAZE_ASSETS_PATH) /
410 static std::filesystem::path cached_cwd;
411 static bool cwd_cached =
false;
415 cached_cwd = std::filesystem::current_path(ec);
419 if (!cached_cwd.empty()) {
421 search_paths.push_back(cached_cwd /
"assets" / relative_path);
428 static std::filesystem::path cached_exe_dir;
429 static bool exe_dir_cached =
false;
431 if (!exe_dir_cached) {
434 char exe_path[PATH_MAX];
435 uint32_t size =
sizeof(exe_path);
436 if (_NSGetExecutablePath(exe_path, &size) == 0) {
437 cached_exe_dir = std::filesystem::path(exe_path).parent_path();
439#elif defined(__linux__)
440 char exe_path[PATH_MAX];
442 readlink(
"/proc/self/exe", exe_path,
sizeof(exe_path) - 1);
444 exe_path[len] =
'\0';
445 cached_exe_dir = std::filesystem::path(exe_path).parent_path();
448 wchar_t exe_path[MAX_PATH];
449 if (GetModuleFileNameW(NULL, exe_path, MAX_PATH) != 0) {
450 cached_exe_dir = std::filesystem::path(exe_path).parent_path();
456 exe_dir_cached =
true;
459 if (!cached_exe_dir.empty()) {
461 search_paths.push_back(cached_exe_dir /
"assets" / relative_path);
463 search_paths.push_back(cached_exe_dir.parent_path() /
"assets" /
469 auto contents_dir = cached_exe_dir.parent_path();
470 auto bundle_dir = contents_dir.parent_path();
471 auto bundle_parent = bundle_dir.parent_path();
472 search_paths.push_back(contents_dir /
"Resources" /
"assets" /
474 search_paths.push_back(bundle_parent /
"assets" / relative_path);
482 if (!cached_cwd.empty()) {
484 auto parent = cached_cwd.parent_path();
485 if (!parent.empty() && parent != cached_cwd) {
486 search_paths.push_back(parent /
"assets" / relative_path);
487 auto grandparent = parent.parent_path();
488 if (!grandparent.empty() && grandparent != parent) {
489 search_paths.push_back(grandparent /
"assets" / relative_path);
498 static std::filesystem::path cached_home;
499 static bool home_cached =
false;
510 if (!cached_home.empty() && cached_home !=
".") {
512 search_paths.push_back(cached_home /
".yaze" /
"assets" /
522 search_paths.push_back(
523 std::filesystem::path(
"/usr/local/share/yaze/assets") /
525 search_paths.push_back(std::filesystem::path(
"/usr/share/yaze/assets") /
534 const size_t max_paths_to_check = 20;
537 for (
const auto& candidate : search_paths) {
538 if (++checked > max_paths_to_check) {
544 std::error_code exists_ec;
545 if (std::filesystem::exists(candidate, exists_ec) && !exists_ec) {
547 auto status = std::filesystem::status(candidate, exists_ec);
549 status.type() != std::filesystem::file_type::not_found) {
560 return absl::NotFoundError(
561 absl::StrCat(
"Asset not found: ", relative_path));
563 }
catch (
const std::exception& e) {
564 return absl::InternalError(
565 absl::StrCat(
"Exception while searching for asset: ", e.what()));
567 return absl::InternalError(
"Unknown exception while searching for asset");