Path.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. #pragma once
  2. #include "Defines.h"
  3. namespace gameplay
  4. {
  5. class Path;
  6. inline Path operator/(const Path& left, const Path& right);
  7. inline Path operator+(const Path& left, const Path& right);
  8. /**
  9. * Paths are used for file system path manipulations.
  10. *
  11. * Paths are all in utf-8 encoding using forward slash as path separator.
  12. * Paths support implicit casting 'std::string'
  13. * Paths support explicit cast to a 'const char*' pointer.
  14. */
  15. class GP_API Path
  16. {
  17. public:
  18. static constexpr const char* EMPTY_STRING = "";
  19. static constexpr char DOT_CHAR = '.';
  20. static constexpr const char* DOT_STRING = ".";
  21. static constexpr size_t DOT_STRING_LENGTH = 1;
  22. static constexpr const char* DOTDOT_STRING = "..";
  23. static constexpr size_t DOTDOT_STRING_LENGTH = 2;
  24. static constexpr char BACKWARD_SLASH_CHAR = '\\';
  25. static constexpr char FORWARD_SLASH_CHAR = '/';
  26. static constexpr const char* FORWARD_SLASH_STRING = "/";
  27. static constexpr size_t FORWARD_SLASH_STRING_LENGTH = 1;
  28. static constexpr char COLON_CHAR = ':';
  29. static constexpr char FIRST_LOWERCASE_LETTER = 'a';
  30. static constexpr char LAST_LOWERCASE_LETTER = 'z';
  31. /**
  32. * Constructor
  33. */
  34. Path();
  35. /**
  36. * Constructor.
  37. *
  38. * Creates a path from a possible non zero-terminated char array containing utf8 string.
  39. *
  40. * @param path A pointer to the data
  41. * @param pathLen the size of the data to be used to create the path object
  42. */
  43. Path(const char* path, size_t pathLen);
  44. /**
  45. * Constructor.
  46. *
  47. * Creates a path from a zero-terminated char array containing utf8 string.
  48. *
  49. * @param path A pointer to the char array
  50. */
  51. Path(const char* path);
  52. /**
  53. *
  54. * Constructor.
  55. *
  56. * Creates a new path from a utf8 std string
  57. *
  58. * @param path The source string
  59. */
  60. Path(std::string path);
  61. /**
  62. * Constructor (Copy).
  63. */
  64. Path(const Path& other);
  65. /**
  66. * Constructor (Copy).
  67. */
  68. Path(Path&& other) noexcept;
  69. /*
  70. * Destructor
  71. */
  72. ~Path();
  73. /**
  74. * Copy operator.
  75. */
  76. Path& operator=(const Path& other);
  77. /**
  78. * Copy operator.
  79. */
  80. Path& operator=(Path&& other) noexcept;
  81. /**
  82. * Gets the std string representation of the path
  83. *
  84. * @return The std::string representation
  85. */
  86. std::string get_string() const;
  87. /**
  88. * Implicit conversion operator to the std string
  89. *
  90. * @return The std::string representation
  91. */
  92. operator std::string() const;
  93. /**
  94. * Get the const char pointer to the path data
  95. *
  96. * @return The c_str pointer to the start of the path data
  97. */
  98. const char* c_str() const;
  99. /**
  100. * Explicit conversion operator to the pointer to const char
  101. *
  102. * @return The c_str pointer to the start of the path data
  103. */
  104. explicit operator const char*() const
  105. {
  106. return c_str();
  107. }
  108. /**
  109. * operator==
  110. */
  111. bool operator==(const Path& other) const;
  112. /**
  113. * operator==
  114. */
  115. bool operator==(const std::string& other) const;
  116. /**
  117. * operator==
  118. */
  119. bool operator==(const char* other) const;
  120. /**
  121. * operator!=
  122. */
  123. bool operator!=(const Path& other) const;
  124. /**
  125. * operator!=
  126. */
  127. bool operator!=(const std::string& other) const;
  128. /**
  129. * operator!=
  130. */
  131. bool operator!=(const char* other) const;
  132. /**
  133. * Gets the length of the path.
  134. *
  135. * @return The length of the path
  136. */
  137. size_t len() const;
  138. /**
  139. * Clears the current path
  140. *
  141. * @return Reference to the current path
  142. */
  143. Path& clear();
  144. /**
  145. * Checks if the path is an empty string
  146. *
  147. * @return true if the path contains at least one character, false otherwise
  148. */
  149. bool is_empty() const;
  150. /**
  151. * Gets the filename component of the path, or an empty path object if there is no filename.
  152. *
  153. * @return The path object representing the filename
  154. */
  155. Path get_filename() const;
  156. /**
  157. * Gets the extension of the filename component of the path, including period (.), or an empty path object.
  158. *
  159. * @return The path object representing the extension
  160. */
  161. Path get_extension() const;
  162. /**
  163. * Gets the path to the parent directory, or an empty path object if there is no parent.
  164. *
  165. * @return The path object representing the parent directory
  166. */
  167. Path get_parent() const;
  168. /**
  169. * Gets the filename component of the path stripped of the extension,
  170. * or an empty path object if there is no filename.
  171. *
  172. * @return The path object representing the stem
  173. */
  174. Path get_stem() const;
  175. /**
  176. * Gets the root name in the path.
  177. *
  178. * @return The path object representing the root name
  179. */
  180. Path get_root_name() const;
  181. /**
  182. * Gets the relative part of the path (the part after optional root name and root directory).
  183. *
  184. * @return The path objects representing the relative part of the path
  185. */
  186. Path get_relative_part() const;
  187. /**
  188. * Gets the root directory if it's present in the path
  189. *
  190. * @return The path object representing the root directory
  191. */
  192. Path get_root_directory() const;
  193. /**
  194. * Checks if the path has a root directory
  195. *
  196. * @return true if the path has a root directory, false if otherwise.
  197. */
  198. bool has_root_directory() const noexcept;
  199. /**
  200. * Gets the root of the path. (root name + root directory, if present)
  201. *
  202. * @return The path object representing the root of the path
  203. */
  204. Path get_root() const;
  205. /**
  206. * Concatenates together two paths without checking for a separator and adding it
  207. *
  208. * @return The path object that has the unified data from the both paths
  209. */
  210. Path concat(const Path& concatedPart) const;
  211. /**
  212. * operator+=
  213. */
  214. Path& operator+=(const Path& path);
  215. /**
  216. * Joins together two path with checking for a separator and adding it if needed
  217. *
  218. * @ return The path object that has the unified data from the both paths
  219. */
  220. Path join(const Path& joinedPart) const;
  221. /**
  222. * operator/=
  223. */
  224. Path& operator/=(const Path& path);
  225. /**
  226. * Replaces the extension part of the current path with a new one.
  227. *
  228. * @param newExtension The path containing the data for the new extension
  229. * @return The current path with the extension changed.
  230. */
  231. Path& replace_extension(const Path& newExtension);
  232. /**
  233. * Gets the absolute path as normalizing the addition of the current path to the root.
  234. *
  235. * @return The path representing the constructed absolute path
  236. */
  237. Path get_absolute(const Path& root = "") const;
  238. /**
  239. * Checks if the current path is an absolute path.
  240. *
  241. * @return True if the current path is an absolute path, false otherwise.
  242. */
  243. bool is_absolute() const;
  244. /**
  245. * Gets the result of the normalization of the current path
  246. *
  247. * @return The new path representing the normalized current path
  248. */
  249. Path get_normalized() const;
  250. /**
  251. * Normalizes current path in place
  252. *
  253. * @return The reference to the current object
  254. */
  255. Path& normalize();
  256. /**
  257. * Gets the current path made relative to base.
  258. *
  259. * The function does NOT normalize the paths prior to the operation.
  260. *
  261. * @param base The base path.
  262. * @return An empty path if it's impossible to match roots (different root names, different states of being
  263. * relative/absolute with a base path, not having a root directory while the base has it), otherwise a non-empty
  264. * relative path
  265. */
  266. Path get_relative(const Path& base) const noexcept;
  267. /**
  268. * Checks if the current path is the relative path.
  269. *
  270. * @return true if the current path is a relative path, false otherwise.
  271. */
  272. bool is_relative() const;
  273. #if GP_PLATFORM_WINDOWS
  274. /**
  275. * Converts a utf-8 file path to Windows system file path.
  276. * Slashes are replaced with backslashes, long path prefix is appended if required.
  277. * @param path Input string to convert, in utf-8 encoding.
  278. * @return The wide string containing Windows system file path or empty string if conversion cannot be performed.
  279. */
  280. static std::wstring convert_utf8_to_windows_path(const std::string& path);
  281. /**
  282. * Converts Windows system file path to a utf-8 file path.
  283. * Backslashes are replaced with slashes, long path prefix is removed.
  284. *
  285. * @param path The input string to convert, in unicode (Windows native) encoding.
  286. * @return The utf-8 encoded file path or empty string if conversion cannot be performed.
  287. */
  288. static std::string convert_windows_to_utf8_path(const std::wstring& path);
  289. /**
  290. * Gets a Windows path string into a canonical form.
  291. * If it's not possible, original path is returned.
  292. *
  293. * @param path The windows system file path, in Unicode (Windows native) encoding.
  294. * @return The canonical form of the input path.
  295. */
  296. static std::wstring get_windows_canonical_path(const std::wstring& path);
  297. /**
  298. * Gets the full path and file name of the specified file.
  299. * If it's not possible, original path is returned.
  300. *
  301. * @param path The Windows system file path, in Unicode (Windows native) encoding.
  302. * @return The full path and file name of the input file.
  303. */
  304. static std::wstring get_windows_full_path(const std::wstring& path);
  305. /**
  306. * Fixes the windows path prefixes.
  307. *
  308. * @param str The windows system fix to be fixed.
  309. */
  310. static std::wstring fix_windows_path_prefixes(const std::wstring& str);
  311. #endif
  312. private:
  313. enum class PathTokenType
  314. {
  315. SLASH,
  316. ROOT_NAME,
  317. DOT,
  318. DOTDOT,
  319. NAME
  320. };
  321. static const char* _get_token_end(const char* bufferBegin, const char* bufferEnd, PathTokenType& resultType);
  322. struct PathPartDesc
  323. {
  324. const char* data;
  325. size_t size;
  326. };
  327. static Path _concat(const PathPartDesc* pathParts, size_t numParts);
  328. template <class Pred = std::equal_to<char>>
  329. static const char* _find_from_end(const char* data, size_t dataSize, char ch)
  330. {
  331. if (!data || dataSize == 0)
  332. {
  333. return nullptr;
  334. }
  335. --data;
  336. Pred pred;
  337. while (dataSize > 0)
  338. {
  339. if (pred(data[dataSize], ch))
  340. {
  341. return data + dataSize;
  342. }
  343. --dataSize;
  344. }
  345. return nullptr;
  346. }
  347. template <class Pred = std::equal_to<char>>
  348. static const char* _find_from_start(const char* data, size_t dataSize, char ch)
  349. {
  350. if (!data || dataSize == 0)
  351. {
  352. return nullptr;
  353. }
  354. Pred pred;
  355. for (const char* const dataEnd = data + dataSize; data != dataEnd; ++data)
  356. {
  357. if (pred(*data, ch))
  358. {
  359. return data;
  360. }
  361. }
  362. return nullptr;
  363. }
  364. const char* _get_filename_ptr() const;
  365. const char* _get_extension_ptr() const;
  366. const char* _get_root_name_end_ptr() const;
  367. const char* _get_relative_part_ptr() const;
  368. const char* _get_root_directory_end_ptr() const;
  369. void _sanitize_path();
  370. std::string _pathStr;
  371. };
  372. inline Path operator+(const Path& left, const Path& right)
  373. {
  374. return left.concat(right);
  375. }
  376. inline Path operator/(const Path& left, const Path& right)
  377. {
  378. return left.join(right);
  379. }
  380. inline Path get_parent_path(std::string path)
  381. {
  382. return Path(std::move(path)).get_parent();
  383. }
  384. inline Path get_path_extension(std::string path)
  385. {
  386. return Path(std::move(path)).get_extension();
  387. }
  388. inline Path get_path_stem(std::string path)
  389. {
  390. return Path(std::move(path)).get_stem();
  391. }
  392. inline Path get_path_relative(std::string path, std::string base)
  393. {
  394. return Path(std::move(path)).get_relative(std::move(base));
  395. }
  396. inline bool operator==(const std::string& left, const Path& right)
  397. {
  398. return right == left;
  399. }
  400. inline bool operator==(const char* left, const Path& right)
  401. {
  402. return right == left;
  403. }
  404. inline bool operator!=(const std::string& left, const Path& right)
  405. {
  406. return right != left;
  407. }
  408. inline bool operator!=(const char* left, const Path& right)
  409. {
  410. return right != left;
  411. }
  412. }