1+ #include " Locate.h"
2+ #include < iostream>
3+ #include < filesystem>
4+ #include < vector>
5+
6+ #if defined(_WIN32)
7+ #include < windows.h>
8+ #elif defined(__APPLE__)
9+ #include < cassert>
10+ #else
11+ #include < unistd.h>
12+ #include < limits.h>
13+ #endif
14+
15+ namespace RAYX {
16+
17+ // Check if a file exists
18+ bool ResourceHandler::fileExists (const std::string& path) { return std::filesystem::exists (path); }
19+ bool ResourceHandler::fileExists (const std::filesystem::path& path) { return std::filesystem::exists (path); }
20+
21+ std::filesystem::path ResourceHandler::getExecutablePath () {
22+ #if defined(_WIN32)
23+ // Start with a reasonable buffer size
24+ std::vector<char > buffer (MAX_PATH);
25+ while (true ) {
26+ // Try to get the module filename
27+ DWORD size = GetModuleFileNameA (NULL , buffer.data (), buffer.size ());
28+ if (size == 0 ) {
29+ return std::filesystem::path ();
30+ }
31+ // If the buffer was large enough, we're done
32+ if (size < buffer.size ()) {
33+ break ;
34+ }
35+ // Otherwise, increase buffer size and try again
36+ buffer.resize (buffer.size () * 2 );
37+ }
38+ #elif defined(__linux__)
39+ // Start with a reasonable buffer size, then grow dynamically if needed
40+ std::vector<char > buffer (PATH_MAX);
41+ ssize_t count;
42+ while (true ) {
43+ count = readlink (" /proc/self/exe" , buffer.data (), buffer.size ());
44+ if (count == -1 ) {
45+ return std::filesystem::path ();
46+ }
47+ if (count < static_cast <ssize_t >(buffer.size ())) {
48+ buffer[count] = ' \0 ' ; // Null-terminate
49+ break ;
50+ }
51+ // If the buffer was too small, increase size and retry
52+ buffer.resize (buffer.size () * 2 );
53+ }
54+
55+ #else
56+ throw std::runtime_error (" getExecutablePath is not implemented for this platform" );
57+ #endif
58+ return std::filesystem::path (buffer.data ());
59+ }
60+
61+ // General method to get the full path based on the base directory (e.g., data or font directory)
62+ std::filesystem::path ResourceHandler::getFullPath (const std::string& baseDir, const std::string& relativePath) {
63+ #if defined(__linux__)
64+ // First, check in /usr (package install)
65+ std::string path = std::string (" /usr/" ) + baseDir + " /" + relativePath;
66+ if (fileExists (path)) return path;
67+
68+ // Next, check next to the executable (built from source)
69+ std::string execDir = getExecutablePath ().string ();
70+ execDir = execDir.substr (0 , execDir.find_last_of (" /\\ " ));
71+ path = execDir + " /" + relativePath;
72+ if (fileExists (path)) return path;
73+
74+ // Lastly, check in /usr/local (make install)
75+ path = std::string (" /usr/local/" ) + baseDir + " /" + relativePath;
76+ if (fileExists (path)) return path;
77+ #elif defined(_WIN32)
78+ // On Windows, only look next to the executable
79+ std::string execDir = getExecutablePath ().string ();
80+ execDir = execDir.substr (0 , execDir.find_last_of (" /\\ " ));
81+ std::filesystem::path path = std::filesystem::path (execDir + " \\ " + relativePath);
82+ if (fileExists (path)) return path;
83+ #elif defined(__APPLE__)
84+ static_assert (false , " macOS support is not implemented yet" );
85+
86+ #endif
87+ // Not found -> empty path
88+ return std::filesystem::path ();
89+ }
90+
91+ // Retrieve the full path of a resource based on the platform
92+ std::filesystem::path ResourceHandler::getResourcePath (const std::string& relativePath) { return getFullPath (RAYX_DATA_DIR, relativePath); }
93+
94+ // Retrieve the full path of a font based on the platform
95+ std::filesystem::path ResourceHandler::getFontPath (const std::string& relativePath) { return getFullPath (RAYX_FONTS_DIR, relativePath); }
96+
97+ } // namespace RAYX
0 commit comments