ResourceLocator.h 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. #ifndef GUL_UTILS_RESOURCE_LOCATOR
  2. #define GUL_UTILS_RESOURCE_LOCATOR
  3. #include<string>
  4. #include<algorithm>
  5. #include<memory>
  6. #include<vector>
  7. #include<stdexcept>
  8. #include<unordered_set>
  9. #include<fstream>
  10. #if defined __linux__
  11. #include <unistd.h>
  12. #include <sys/stat.h>
  13. #include <unistd.h>
  14. #include <pwd.h>
  15. #endif
  16. #if defined _WIN32
  17. #include <windows.h>
  18. #include <direct.h>
  19. #include <stdlib.h>
  20. #endif
  21. #if defined __APPLE__
  22. #include <unistd.h>
  23. #include <libproc.h>
  24. #endif
  25. #if __has_include(<filesystem>)
  26. #include <filesystem>
  27. namespace gul
  28. {
  29. namespace fs = std::filesystem;
  30. }
  31. #elif __has_include(<experimental/filesystem>)
  32. #include <experimental/filesystem>
  33. namespace gul
  34. {
  35. namespace fs = std::experimental::filesystem;
  36. }
  37. #else
  38. #error There is no <filesystem> or <experimental/filesystem>
  39. #endif
  40. namespace gul
  41. {
  42. /**
  43. * @brief getExecutablePath
  44. * @return
  45. *
  46. * Returns the path to the current executable
  47. */
  48. inline std::string getExecutablePath()
  49. {
  50. char path[FILENAME_MAX];
  51. #if defined __linux__
  52. auto i = readlink("/proc/self/exe", path, FILENAME_MAX );
  53. path[i] = 0;
  54. return path;
  55. #elif defined _WIN32
  56. auto i = GetModuleFileNameA( NULL, path, FILENAME_MAX);
  57. auto p = path_type( path );
  58. return join( get_cwd(), path);
  59. #elif defined __APPLE__
  60. char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
  61. auto pid = getpid();
  62. auto ret = proc_pidpath (pid, pathbuf, sizeof(pathbuf));
  63. if ( ret <= 0 ) {
  64. return "";
  65. } else {
  66. return pathbuf;
  67. }
  68. #endif
  69. }
  70. /**
  71. * @brief The ResourceLocator class
  72. *
  73. * The resources container allows you to add root paths to it. for example
  74. *
  75. * ResourceLocator r;
  76. * r.push_back("/usr/bin");
  77. * r.push_back("/usr/local/bin");
  78. * r.push_back("/bin");
  79. *
  80. * And then search for files relatives to the rooth paths.
  81. *
  82. * assert( r.get("bash") == "/bin/bash");
  83. *
  84. */
  85. class ResourceLocator
  86. {
  87. public:
  88. std::vector< fs::path > roots;
  89. /**
  90. * @brief addPath
  91. * @param path
  92. *
  93. * Add a path to the set of resource paths.
  94. */
  95. void push_back(fs::path const& absPath)
  96. {
  97. if( !absPath.is_absolute() )
  98. {
  99. throw std::runtime_error("Must be an absolute path");
  100. }
  101. roots.push_back(absPath);
  102. }
  103. /**
  104. * @brief clearPaths
  105. *
  106. * Clear all the paths.
  107. */
  108. void clear()
  109. {
  110. roots.clear();
  111. }
  112. size_t size() const
  113. {
  114. return roots.size();
  115. }
  116. std::vector<uint8_t> readResourceBIN(const fs::path &relPath) const
  117. {
  118. auto path = locate(relPath);
  119. if( path == "")
  120. {
  121. throw std::invalid_argument( std::string("File does not exist: ") + relPath.string());
  122. }
  123. std::ifstream stream(path, std::ios::in | std::ios::binary);
  124. std::vector<uint8_t> contents((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>());
  125. return contents;
  126. }
  127. std::string readResourceASCII(const fs::path &relPath) const
  128. {
  129. auto path = locate(relPath);
  130. if( path == "")
  131. {
  132. throw std::invalid_argument( std::string("File does not exist: ") + relPath.string());
  133. }
  134. std::ifstream t( path );
  135. if(!t)
  136. {
  137. throw std::invalid_argument( std::string("Unable to open file: ") + path.string());
  138. }
  139. std::string asciiSrc((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
  140. return asciiSrc;
  141. }
  142. /**
  143. * @brief locate
  144. * @param file_name
  145. * @return
  146. *
  147. * Locate a resource, returns the absolute path to the
  148. * resource
  149. */
  150. fs::path locate(fs::path const& relPath) const
  151. {
  152. for(auto const & p1 : roots )
  153. {
  154. auto abs_path = p1 / relPath;
  155. if( fs::exists(abs_path) )
  156. {
  157. return abs_path;
  158. }
  159. }
  160. return {};
  161. }
  162. /**
  163. * @brief listDirectory
  164. * @param dirPath
  165. * @return
  166. *
  167. * Returns a vector of file paths contained in dirPath.
  168. *
  169. * dirPath must be a relative path
  170. */
  171. std::vector<fs::path> listDirectory( fs::path const & dirPath, fs::directory_options opt = fs::directory_options::none) const
  172. {
  173. auto absDirPath = locate(dirPath);
  174. if( !fs::is_directory(absDirPath) )
  175. {
  176. throw std::runtime_error("Must be a directory path");
  177. }
  178. std::vector<fs::path> out;
  179. for(auto& p: fs::directory_iterator( absDirPath, opt ) )
  180. {
  181. out.push_back( p );
  182. }
  183. return out;
  184. }
  185. /**
  186. * @brief locateAll
  187. * @param relPath
  188. * @return
  189. *
  190. * Locates a list of all paths that match ROOT[i]/relPath
  191. * And returns the root path for which it exists in.
  192. */
  193. std::vector<fs::path> locateAll( fs::path const & relPath) const
  194. {
  195. std::vector<fs::path> all;
  196. for(auto const & p1 : roots )
  197. {
  198. auto abs_path = p1 / relPath;
  199. if( fs::exists(abs_path) )
  200. {
  201. all.push_back( p1 );
  202. }
  203. }
  204. return all;
  205. }
  206. /**
  207. * @brief listDirectoryUnion
  208. * @param dirPath
  209. * @return
  210. *
  211. * Given a relative path, lists all the files that exist in that
  212. * directory, but do not include duplicated file names.
  213. * For example if the root paths are: /tmp/A and /tmp/B
  214. * and the dir structure is
  215. *
  216. * /tmp/A/File1
  217. * /tmp/A/File2
  218. * /tmp/B/File1
  219. * /tmp/B/File3
  220. *
  221. * It will return: /tmp/A/File1, /tmp/A/File2, /tmp/B/File3
  222. *
  223. * /tmp/B/File1 will not be returned because it is shadowded
  224. * by a previous root path
  225. */
  226. std::vector<fs::path> listDirectoryUnion( fs::path const & relPath, fs::directory_options opt = fs::directory_options::none) const
  227. {
  228. // locate all the paths that match ROOT[i]/relPath
  229. auto validDirs = locateAll(relPath);
  230. std::unordered_set<std::string> found;
  231. std::vector<fs::path> unionFiles;
  232. for(auto const & p1 : validDirs)
  233. {
  234. auto n = p1.string().size();
  235. auto dirPath = p1/relPath;
  236. if( fs::is_directory(dirPath))
  237. {
  238. for(auto & p: fs::directory_iterator( dirPath, opt ) )
  239. {
  240. auto leaf = p.path().string().erase(0,n+1);
  241. if( found.insert(leaf).second == true)
  242. {
  243. unionFiles.push_back( p );
  244. }
  245. }
  246. }
  247. }
  248. return unionFiles;
  249. }
  250. };
  251. }
  252. #endif