VCMIDirs.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. /*
  2. * VCMIDirs.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "VCMIDirs.h"
  12. namespace bfs = boost::filesystem; // Should be in each cpp file
  13. #ifdef _WIN32
  14. // File: VCMIDirs_win32.h
  15. //#include "IVCMIDirs.h"
  16. class VCMIDirs_win32 : public IVCMIDirs
  17. {
  18. public:
  19. boost::filesystem::path userDataPath() const override;
  20. boost::filesystem::path userCachePath() const override;
  21. boost::filesystem::path userConfigPath() const override;
  22. boost::filesystem::path userSavePath() const override;
  23. std::vector<boost::filesystem::path> dataPaths() const override;
  24. boost::filesystem::path clientPath() const override;
  25. boost::filesystem::path serverPath() const override;
  26. boost::filesystem::path libraryPath() const override;
  27. boost::filesystem::path binaryPath() const override;
  28. std::string libraryName(const std::string& basename) const override;
  29. std::string genHelpString() const override;
  30. };
  31. // End of file: VCMIDirs_win32.h
  32. // File: VCMIDirs_win32.cpp
  33. //#include "StdInc.h"
  34. //#include "VCMIDirs_win32"
  35. // WinAPI
  36. #include <Windows.h> // WideCharToMultiByte
  37. #include <Shlobj.h> // SHGetSpecialFolderPathW
  38. namespace VCMIDirs
  39. {
  40. const IVCMIDirs& get()
  41. {
  42. static VCMIDirs_win32 singleton;
  43. return singleton;
  44. }
  45. }
  46. bfs::path VCMIDirs_win32::userDataPath() const
  47. {
  48. const char* profile_dir_a;
  49. wchar_t profile_dir_w[MAX_PATH];
  50. // The user's profile folder. A typical path is C:\Users\username.
  51. // FIXME: Applications should not create files or folders at this level;
  52. // they should put their data under the locations referred to by CSIDL_APPDATA or CSIDL_LOCAL_APPDATA.
  53. if (SHGetSpecialFolderPathW(nullptr, profile_dir_w, CSIDL_PROFILE, FALSE) == FALSE) // WinAPI way failed
  54. {
  55. // FIXME: Create macro for MS Visual Studio.
  56. if (profile_dir_a = std::getenv("userprofile")) // STL way succeed
  57. return bfs::path(profile_dir_a) / "vcmi";
  58. else
  59. return "."; // Every thing failed, return current directory.
  60. }
  61. else
  62. return bfs::path(profile_dir_w) / "vcmi";
  63. //return dataPaths()[0] ???;
  64. }
  65. bfs::path VCMIDirs_win32::userCachePath() const { return userDataPath(); }
  66. bfs::path VCMIDirs_win32::userConfigPath() const { return userDataPath() / "config"; }
  67. bfs::path VCMIDirs_win32::userSavePath() const { return userDataPath() / "Games"; }
  68. std::vector<bfs::path> VCMIDirs_win32::dataPaths() const
  69. {
  70. return std::vector<bfs::path>(1, bfs::path("."));
  71. }
  72. bfs::path VCMIDirs_win32::clientPath() const { return binaryPath() / "VCMI_client.exe"; }
  73. bfs::path VCMIDirs_win32::serverPath() const { return binaryPath() / "VCMI_server.exe"; }
  74. bfs::path VCMIDirs_win32::libraryPath() const { return "."; }
  75. bfs::path VCMIDirs_win32::binaryPath() const { return "."; }
  76. std::string VCMIDirs_win32::genHelpString() const
  77. {
  78. // I think this function should have multiple versions
  79. // 1. For various arguments
  80. // 2. Inverse functions
  81. // and should be moved to vstd
  82. // or use http://utfcpp.sourceforge.net/
  83. auto utf8_convert = [](const bfs::path& path) -> std::string
  84. {
  85. const auto& path_string = path.native();
  86. auto perform_convert = [&path_string](LPSTR output, int output_size)
  87. {
  88. return WideCharToMultiByte(
  89. CP_UTF8, // Use wchar_t -> utf8 char_t
  90. WC_ERR_INVALID_CHARS, // Fails when invalid char occur
  91. path_string.c_str(), // String to convert
  92. path_string.size(), // String to convert size
  93. output, // Result
  94. output_size, // Result size
  95. nullptr, nullptr); // For the ... CP_UTF8 settings for CodePage, this parameter must be set to NULL
  96. };
  97. int char_count = perform_convert(nullptr, 0); // Result size (0 - obtain size)
  98. if (char_count > 0)
  99. {
  100. std::unique_ptr<char[]> buffer(new char[char_count]);
  101. if ((char_count = perform_convert(buffer.get(), char_count)) > 0)
  102. return std::string(buffer.get(), char_count);
  103. }
  104. // Conversion failed :C
  105. return path.string();
  106. };
  107. std::vector<std::string> temp_vec;
  108. for (const bfs::path& path : dataPaths())
  109. temp_vec.push_back(utf8_convert(path));
  110. std::string gd_string_a = boost::algorithm::join(temp_vec, L";");
  111. return
  112. " game data: " + gd_string_a + "\n" +
  113. " libraries: " + utf8_convert(libraryPath()) + "\n" +
  114. " server: " + utf8_convert(serverPath()) + "\n" +
  115. "\n" +
  116. " user data: " + utf8_convert(userDataPath()) + "\n" +
  117. " user cache: " + utf8_convert(userCachePath()) + "\n" +
  118. " user config: " + utf8_convert(userConfigPath()) + "\n" +
  119. " user saves: " + utf8_convert(userSavePath()) + "\n"; // Should end without new-line?
  120. }
  121. std::string VCMIDirs_win32::libraryName(const std::string& basename) const { return basename + ".dll"; }
  122. // End of file: VCMIDirs_win32.cpp
  123. #else // UNIX
  124. // File: IVCMIDirs_UNIX.h
  125. //#include "IVCMIDirs.h"
  126. class IVCMIDirs_UNIX : public IVCMIDirs
  127. {
  128. public:
  129. boost::filesystem::path clientPath() const override;
  130. boost::filesystem::path serverPath() const override;
  131. std::string genHelpString() const override;
  132. };
  133. // End of file: IVCMIDirs_UNIX.h
  134. // File: IVCMIDirs_UNIX.cpp
  135. //#include "StdInc.h"
  136. //#include "IVCMIDirs_UNIX.h"
  137. bfs::path IVCMIDirs_UNIX::clientPath() const { return binaryPath() / "vcmiclient"; }
  138. bfs::path IVCMIDirs_UNIX::clientPath() const { return binaryPath() / "vcmiserver"; }
  139. std::string IVCMIDirs_UNIX::genHelpString() const
  140. {
  141. std::vector<std::string> temp_vec;
  142. for (const bfs::path& path : dataPaths())
  143. temp_vec.push_back(path.string());
  144. std::string gd_string_a = boost::algorithm::join(temp_vec, L";");
  145. return
  146. " game data: " + gd_string_a + "\n" +
  147. " libraries: " + libraryPath().string() + "\n" +
  148. " server: " + serverPath().string() + "\n" +
  149. "\n" +
  150. " user data: " + userDataPath().string() + "\n" +
  151. " user cache: " + userCachePath().string() + "\n" +
  152. " user config: " + userConfigPath().string() + "\n" +
  153. " user saves: " + userSavePath().string() + "\n"; // Should end without new-line?
  154. }
  155. // End of file: IVCMIDirs_UNIX.cpp
  156. #ifdef __APPLE__
  157. // File: VCMIDirs_OSX.h
  158. //#include "IVCMIDirs_UNIX.h"
  159. class VCMIDirs_OSX : public IVCMIDirs_UNIX
  160. {
  161. public:
  162. boost::filesystem::path userDataPath() const override;
  163. boost::filesystem::path userCachePath() const override;
  164. boost::filesystem::path userConfigPath() const override;
  165. boost::filesystem::path userSavePath() const override;
  166. std::vector<boost::filesystem::path> dataPaths() const override;
  167. boost::filesystem::path libraryPath() const override;
  168. boost::filesystem::path binaryPath() const override;
  169. std::string libraryName(const std::string& basename) const override;
  170. };
  171. // End of file: VCMIDirs_OSX.h
  172. // File: VCMIDirs_OSX.cpp
  173. //#include "StdInc.h"
  174. //#include "VCMIDirs_OSX.h"
  175. namespace VCMIDirs
  176. {
  177. const IVCMIDirs& get()
  178. {
  179. static VCMIDirs_OSX singleton;
  180. return singleton;
  181. }
  182. }
  183. bfs::path VCMIDirs_OSX::userDataPath() const
  184. {
  185. // This is Cocoa code that should be normally used to get path to Application Support folder but can't use it here for now...
  186. // NSArray* urls = [[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask];
  187. // UserPath = path([urls[0] path] + "/vcmi").string();
  188. // ...so here goes a bit of hardcode instead
  189. const char* home_dir = getenv("HOME"); // Should be std::getenv?
  190. if (home_dir == nullptr)
  191. home_dir = ".";
  192. return bfs::path(home_dir) / "Library" / "Application Support" / "vcmi";
  193. }
  194. bfs::path VCMIDirs_OSX::userCachePath() const { return userDataPath(); }
  195. bfs::path VCMIDirs_OSX::userConfigPath() const { return userDataPath() / "config"; }
  196. bfs::path VCMIDirs_OSX::userSavePath() const { return userDataPath() / "Games"; }
  197. std::vector<bfs::path> VCMIDirs_OSX::dataPaths() const
  198. {
  199. return std::vector<bfs::path>(1, "../Data");
  200. }
  201. bfs::path VCMIDirs_OSX::libraryPath() const { return "."; }
  202. bfs::path VCMIDirs_OSX::binaryPath() const { return "."; }
  203. std::string libraryName(const std::string& basename) { return "lib" + basename + ".dylib"; }
  204. // End of file: VCMIDirs_OSX.cpp
  205. #else
  206. // File: VCMIDirs_Linux.h
  207. //#include "IVCMIDirs_UNIX.h"
  208. class VCMIDirs_Linux : public IVCMIDirs_UNIX
  209. {
  210. public:
  211. boost::filesystem::path userDataPath() const override;
  212. boost::filesystem::path userCachePath() const override;
  213. boost::filesystem::path userConfigPath() const override;
  214. boost::filesystem::path userSavePath() const override;
  215. std::vector<boost::filesystem::path> dataPaths() const override;
  216. boost::filesystem::path libraryPath() const override;
  217. boost::filesystem::path binaryPath() const override;
  218. std::string libraryName(const std::string& basename) const override;
  219. };
  220. // End of file: VCMIDirs_Linux.h
  221. // File: VCMIDirs_Linux.cpp
  222. //#include "StdInc.h"
  223. //#include "VCMIDirs_Linux.h"
  224. namespace VCMIDirs
  225. {
  226. const IVCMIDirs& get()
  227. {
  228. static VCMIDirs_Linux singleton;
  229. return singleton;
  230. }
  231. }
  232. bfs::path VCMIDirs_Linux::userDataPath() const
  233. {
  234. // $XDG_DATA_HOME, default: $HOME/.local/share
  235. const char* home_dir;
  236. if (home_dir = getenv("XDG_DATA_HOME"))
  237. return home_dir;
  238. else if (home_dir = getenv("HOME"))
  239. return bfs::path(home_dir) / ".local" / "share" / "vcmi";
  240. else
  241. return ".";
  242. }
  243. bfs::path VCMIDirs_Linux::userCachePath() const
  244. {
  245. // $XDG_CACHE_HOME, default: $HOME/.cache
  246. const char* home_dir;
  247. if (home_dir = getenv("XDG_CACHE_HOME"))
  248. return bfs::path(home_dir) / "vcmi";
  249. else if (home_dir = getenv("HOME"))
  250. return bfs::path(home_dir) / ".cache" / "vcmi";
  251. else
  252. return ".";
  253. }
  254. bfs::path VCMIDirs_Linux::userConfigPath() const
  255. {
  256. // $XDG_CONFIG_HOME, default: $HOME/.config
  257. const char* home_dir;
  258. if (home_dir = getenv("XDG_CONFIG_HOME"))
  259. return bfs::path(home_dir) / "vcmi";
  260. else if (home_dir = getenv("HOME"))
  261. return bfs::path(home_dir) / ".config" / "vcmi";
  262. else
  263. return ".";
  264. }
  265. bfs::path VCMIDirs_Linux::userSavePath() const
  266. {
  267. return userDataPath() / "Saves";
  268. }
  269. std::vector<bfs::path> VCMIDirs_Linux::dataPaths() const
  270. {
  271. // $XDG_DATA_DIRS, default: /usr/local/share/:/usr/share/
  272. // construct list in reverse.
  273. // in specification first directory has highest priority
  274. // in vcmi fs last directory has highest priority
  275. std::vector<bfs::path> ret;
  276. const char* home_dir;
  277. if (home_dir = getenv("HOME")) // compatibility, should be removed after 0.96
  278. ret.push_back(bfs::path(home_dir) / ".vcmi");
  279. ret.push_back(M_DATA_DIR);
  280. if ((home_dir = getenv("XDG_DATA_DIRS")) != nullptr)
  281. {
  282. std::string dataDirsEnv = home_dir;
  283. std::vector<std::string> dataDirs;
  284. boost::split(dataDirs, dataDirsEnv, boost::is_any_of(":"));
  285. for (auto & entry : boost::adaptors::reverse(dataDirs))
  286. ret.push_back(entry + "/vcmi");
  287. }
  288. else
  289. {
  290. ret.push_back("/usr/share/");
  291. ret.push_back("/usr/local/share/");
  292. }
  293. return ret;
  294. }
  295. bfs::path VCMIDirs_Linux::libraryPath() const { return M_LIB_PATH; }
  296. bfs::path VCMIDirs_Linux::binaryPath() const { return M_BIN_DIR; }
  297. std::string VCMIDirs_Linux::libraryName(const std::string& basename) const { return "lib" + basename + ".so"; }
  298. // End of file VCMIDirs_Linux.cpp
  299. #ifdef __ANDROID__
  300. // File: VCMIDirs_Android.h
  301. //#include "VCMIDirs_Linux.h"
  302. class VCMIDirs_Android : public VCMIDirs_Linux
  303. {
  304. public:
  305. boost::filesystem::path userDataPath() const override;
  306. boost::filesystem::path userCachePath() const override;
  307. boost::filesystem::path userConfigPath() const override;
  308. boost::filesystem::path userSavePath() const override;
  309. std::vector<boost::filesystem::path> dataPaths() const override;
  310. };
  311. // End of file: VCMIDirs_Android.h
  312. // File: VCMIDirs_Android.cpp
  313. //#include "StdInc.h"
  314. //#include "VCMIDirs_Android.h"
  315. namespace VCMIDirs
  316. {
  317. const IVCMIDirs& get()
  318. {
  319. static VCMIDirs_Android singleton;
  320. return singleton;
  321. }
  322. }
  323. // on Android HOME will be set to something like /sdcard/data/Android/is.xyz.vcmi/files/
  324. bfs::path VCMIDirs_Android::userDataPath() const { return getenv("HOME"); }
  325. bfs::path VCMIDirs_Android::userCachePath() const { return userDataPath() / "cache"; }
  326. bfs::path VCMIDirs_Android::userConfigPath() const { return userDataPath() / "config"; }
  327. bfs::path VCMIDirs_Android::userSavePath() const { return userDataPath() / "Saves"; }
  328. std::vector<bfs::path> VCMIDirs_Android::dataPaths() const
  329. {
  330. return std::vector<bfs::path>(1, userDataPath());
  331. }
  332. // End of file: VCMIDirs_Android.cpp
  333. #endif
  334. #endif
  335. #endif