File.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. /*
  2. * Author: Patrick-Christopher Mattulat
  3. * Company: Lynar Studios
  4. * E-Mail: webmaster@lynarstudios.com
  5. * Created: 2020-08-15
  6. * Changed: 2023-02-05
  7. *
  8. * */
  9. #include <algorithm>
  10. #include <cstdio>
  11. #ifdef _WIN32
  12. #include <direct.h>
  13. #endif
  14. #include <fstream>
  15. #include <ls-std/core/exception/FileOperationException.hpp>
  16. #include <ls-std/io/File.hpp>
  17. #include <ls-std/io/FilePathSeparator.hpp>
  18. #include <ls-std/io/FilePathSeparatorMatch.hpp>
  19. #include <sstream>
  20. #include <sys/stat.h>
  21. #ifdef _WIN32
  22. #include <tchar.h>
  23. #endif
  24. #if defined(unix) || defined(__APPLE__)
  25. #include <unistd.h>
  26. #endif
  27. #include <vector>
  28. ls::std::io::File::File(::std::string _absoluteFilePath) : ls::std::core::Class("File"), absoluteFilePath(ls::std::io::File::_normalizePath(::std::move(_absoluteFilePath)))
  29. {}
  30. ls::std::io::File::~File() = default;
  31. bool ls::std::io::File::operator==(ls::std::io::File &_file)
  32. {
  33. return ls::std::io::File::_equals(*this, _file);
  34. }
  35. bool ls::std::io::File::operator!=(ls::std::io::File &_file)
  36. {
  37. return !ls::std::io::File::_equals(*this, _file);
  38. }
  39. bool ls::std::io::File::canExecute()
  40. {
  41. return ls::std::io::File::_isExecutable(this->absoluteFilePath);
  42. }
  43. bool ls::std::io::File::canRead()
  44. {
  45. bool readable;
  46. #if defined(unix) || defined(__APPLE__)
  47. readable = ls::std::io::File::_isReadableUnix(this->absoluteFilePath);
  48. #endif
  49. #ifdef _WIN32
  50. readable = ls::std::io::File::_isReadableWindows(this->absoluteFilePath);
  51. #endif
  52. return readable;
  53. }
  54. bool ls::std::io::File::canWrite()
  55. {
  56. return ls::std::io::File::_isWritable(this->absoluteFilePath);
  57. }
  58. void ls::std::io::File::createNewFile()
  59. {
  60. if (!ls::std::io::File::_exists(this->absoluteFilePath))
  61. {
  62. ::std::ofstream file{this->absoluteFilePath};
  63. file.close();
  64. }
  65. else
  66. {
  67. throw ls::std::core::FileOperationException{};
  68. }
  69. }
  70. bool ls::std::io::File::exists()
  71. {
  72. return ls::std::io::File::_exists(this->absoluteFilePath);
  73. }
  74. ::std::string ls::std::io::File::getAbsoluteFilePath()
  75. {
  76. return this->absoluteFilePath;
  77. }
  78. ::std::string ls::std::io::File::getName()
  79. {
  80. ::std::string copy = this->absoluteFilePath;
  81. // if it's a directory, remove separator from end, if it does exist
  82. if (ls::std::io::File::_isDirectory(this->absoluteFilePath))
  83. {
  84. copy.erase(::std::remove_if(copy.end() - 1, copy.end(), ls::std::io::FilePathSeparatorMatch()), copy.end());
  85. }
  86. // now get the file / directory name
  87. auto base = ::std::find_if(copy.rbegin(), copy.rend(), ls::std::io::FilePathSeparatorMatch()).base();
  88. return ::std::string{base, copy.end()};
  89. }
  90. ::std::string ls::std::io::File::getParent()
  91. {
  92. return ls::std::io::File::_getParent(this->absoluteFilePath);
  93. }
  94. ::std::string ls::std::io::File::getWorkingDirectory()
  95. {
  96. ::std::string workingDirectory{};
  97. #if defined(unix) || defined(__APPLE__)
  98. workingDirectory = ls::std::io::File::_getWorkingDirectoryUnix();
  99. #endif
  100. #ifdef _WIN32
  101. workingDirectory = ls::std::io::File::_getWorkingDirectoryWindows();
  102. #endif
  103. return workingDirectory;
  104. }
  105. long ls::std::io::File::getSize()
  106. {
  107. ::std::streampos fileSize{};
  108. if (ls::std::io::File::_exists(this->absoluteFilePath))
  109. {
  110. ::std::ifstream fileHandler{this->absoluteFilePath, ::std::ios::in};
  111. fileSize = fileHandler.tellg();
  112. fileHandler.seekg(0, ::std::ios::end);
  113. fileSize = fileHandler.tellg() - fileSize;
  114. fileHandler.close();
  115. }
  116. return (long) fileSize;
  117. }
  118. bool ls::std::io::File::isDirectory()
  119. {
  120. return ls::std::io::File::_isDirectory(this->absoluteFilePath);
  121. }
  122. bool ls::std::io::File::isFile()
  123. {
  124. return ls::std::io::File::_isFile(this->absoluteFilePath);
  125. }
  126. time_t ls::std::io::File::lastModified()
  127. {
  128. return ls::std::io::File::_lastModified(this->absoluteFilePath);
  129. }
  130. ::std::list<::std::string> ls::std::io::File::list()
  131. {
  132. ::std::list<::std::string> fileList{};
  133. if (ls::std::io::File::_isDirectory(this->absoluteFilePath))
  134. {
  135. fileList = ls::std::io::File::_list(this->absoluteFilePath);
  136. }
  137. return fileList;
  138. }
  139. ::std::list<::std::string> ls::std::io::File::listFiles()
  140. {
  141. ::std::list<::std::string> fileList{};
  142. if (ls::std::io::File::_isDirectory(this->absoluteFilePath))
  143. {
  144. fileList = ls::std::io::File::_listFiles(this->absoluteFilePath);
  145. }
  146. return fileList;
  147. }
  148. void ls::std::io::File::makeDirectory()
  149. {
  150. if (ls::std::io::File::_mkdir(this->absoluteFilePath))
  151. {
  152. throw ls::std::core::FileOperationException{};
  153. }
  154. }
  155. void ls::std::io::File::makeDirectories()
  156. {
  157. ::std::vector<::std::string> subDirectories = ls::std::io::File::_splitIntoSubDirectoryNames(this->absoluteFilePath);
  158. const char separator = ls::std::io::FilePathSeparator::get();
  159. ::std::string currentHierarchy{};
  160. for (const auto &subDirectory : subDirectories)
  161. {
  162. currentHierarchy += subDirectory;
  163. if (!ls::std::io::File::_exists(currentHierarchy))
  164. {
  165. ls::std::io::File::_mkdir(currentHierarchy);
  166. }
  167. currentHierarchy += separator;
  168. }
  169. }
  170. void ls::std::io::File::remove()
  171. {
  172. if (ls::std::io::File::_isFile(this->absoluteFilePath))
  173. {
  174. ::std::remove(this->absoluteFilePath.c_str());
  175. }
  176. if (ls::std::io::File::_isDirectory(this->absoluteFilePath))
  177. {
  178. ls::std::io::File::_remove(this->absoluteFilePath);
  179. }
  180. }
  181. bool ls::std::io::File::renameTo(const ::std::string &_newName)
  182. {
  183. bool renamed = ls::std::io::File::_renameTo(this->absoluteFilePath, _newName);
  184. if (renamed)
  185. {
  186. this->absoluteFilePath = _newName;
  187. }
  188. return renamed;
  189. }
  190. void ls::std::io::File::reset(const ::std::string &_newPath)
  191. {
  192. this->absoluteFilePath = ls::std::io::File::_normalizePath(_newPath);
  193. }
  194. #ifdef _WIN32
  195. void ls::std::io::File::_addToFileListWindows(const ::std::string &_path, bool _withDirectories, WIN32_FIND_DATA _data, ::std::list<::std::string> &_list)
  196. {
  197. const char separator = ls::std::io::FilePathSeparator::get();
  198. ::std::string absolutePath = _path + separator + _data.cFileName;
  199. if (_withDirectories)
  200. {
  201. _list.emplace_back(absolutePath);
  202. }
  203. else
  204. {
  205. if (ls::std::io::File::_isFile(absolutePath))
  206. {
  207. _list.emplace_back(absolutePath);
  208. }
  209. }
  210. }
  211. #endif
  212. #if defined(unix) || defined(__APPLE__)
  213. void ls::std::io::File::_addToFileListUnix(const ::std::string &_path, bool _withDirectories, dirent *directoryEntity, ::std::list<::std::string> &_list)
  214. {
  215. const char separator = ls::std::io::FilePathSeparator::get();
  216. ::std::string absolutePath = _path + separator + directoryEntity->d_name;
  217. if (_withDirectories)
  218. {
  219. _list.emplace_back(absolutePath);
  220. }
  221. else
  222. {
  223. if (ls::std::io::File::_isFile(absolutePath))
  224. {
  225. _list.emplace_back(absolutePath);
  226. }
  227. }
  228. }
  229. #endif
  230. bool ls::std::io::File::_equals(ls::std::io::File &_file, ls::std::io::File &_foreignFile)
  231. {
  232. bool isEqual = _file.getAbsoluteFilePath() == _foreignFile.getAbsoluteFilePath();
  233. if (_file.exists() && _foreignFile.exists())
  234. {
  235. isEqual = isEqual && _file.canRead() == _foreignFile.canRead();
  236. isEqual = isEqual && _file.canWrite() == _foreignFile.canWrite();
  237. isEqual = isEqual && _file.canExecute() == _foreignFile.canExecute();
  238. }
  239. return isEqual;
  240. }
  241. bool ls::std::io::File::_exists(const ::std::string &_path)
  242. {
  243. struct stat _stat
  244. {
  245. };
  246. return (stat(_path.c_str(), &_stat) == 0);
  247. }
  248. ::std::string ls::std::io::File::_getParent(const ::std::string &_path)
  249. {
  250. ::std::string parent{};
  251. ::std::vector<::std::string> subDirectoryNames = ls::std::io::File::_splitIntoSubDirectoryNames(_path);
  252. const char separator = ls::std::io::FilePathSeparator::get();
  253. subDirectoryNames.pop_back();
  254. for (auto const &subDirectoryName : subDirectoryNames)
  255. {
  256. parent += subDirectoryName + separator;
  257. }
  258. return parent;
  259. }
  260. #if defined(unix) || defined(__APPLE__)
  261. ::std::string ls::std::io::File::_getWorkingDirectoryUnix()
  262. {
  263. ::std::string workingDirectory{};
  264. char buffer[PATH_MAX];
  265. if (getcwd(buffer, sizeof(buffer)) == nullptr)
  266. {
  267. throw ls::std::core::FileOperationException{};
  268. }
  269. else
  270. {
  271. workingDirectory = ::std::string(buffer);
  272. }
  273. return workingDirectory;
  274. }
  275. #endif
  276. #ifdef _WIN32
  277. ::std::string ls::std::io::File::_getWorkingDirectoryWindows()
  278. {
  279. ::std::string workingDirectory{};
  280. TCHAR buffer[MAX_PATH];
  281. if (!GetCurrentDirectory(MAX_PATH, buffer))
  282. {
  283. throw ls::std::core::FileOperationException{};
  284. }
  285. else
  286. {
  287. workingDirectory = ::std::string(buffer);
  288. }
  289. return workingDirectory;
  290. }
  291. #endif
  292. bool ls::std::io::File::_isDirectory(const ::std::string &_path)
  293. {
  294. bool match{};
  295. struct stat _stat
  296. {
  297. };
  298. if (stat(_path.c_str(), &_stat) == 0)
  299. {
  300. match = _stat.st_mode & (unsigned short) S_IFDIR;
  301. }
  302. return match;
  303. }
  304. bool ls::std::io::File::_isExecutable(const ::std::string &_path)
  305. {
  306. bool executable{};
  307. if (ls::std::io::File::_exists(_path))
  308. {
  309. struct stat _stat
  310. {
  311. };
  312. if (stat(_path.c_str(), &_stat) == 0)
  313. {
  314. executable = (_stat.st_mode & (unsigned short) S_IEXEC) != 0;
  315. }
  316. }
  317. return executable;
  318. }
  319. bool ls::std::io::File::_isFile(const ::std::string &_path)
  320. {
  321. bool match{};
  322. struct stat _stat
  323. {
  324. };
  325. if (stat(_path.c_str(), &_stat) == 0)
  326. {
  327. match = _stat.st_mode & (unsigned) S_IFREG;
  328. }
  329. return match;
  330. }
  331. #if defined(unix) || defined(__APPLE__)
  332. bool ls::std::io::File::_isReadableUnix(const ::std::string &_path)
  333. {
  334. bool readable{};
  335. if (ls::std::io::File::_exists(_path))
  336. {
  337. struct stat _stat
  338. {
  339. };
  340. if (stat(_path.c_str(), &_stat) == 0)
  341. {
  342. readable = (_stat.st_mode & (unsigned) S_IREAD) != 0;
  343. }
  344. }
  345. else
  346. {
  347. throw ls::std::core::FileOperationException{};
  348. }
  349. return readable;
  350. }
  351. #endif
  352. #ifdef _WIN32
  353. bool ls::std::io::File::_isReadableWindows(const ::std::string &_path)
  354. {
  355. bool readable;
  356. WIN32_FIND_DATA data{};
  357. HANDLE handleFind = FindFirstFile(_path.c_str(), &data);
  358. if (handleFind != INVALID_HANDLE_VALUE)
  359. {
  360. readable = GetFileAttributes(data.cFileName) & (unsigned) FILE_ATTRIBUTE_READONLY;
  361. }
  362. else
  363. {
  364. throw ls::std::core::FileOperationException{};
  365. }
  366. return readable;
  367. }
  368. #endif
  369. bool ls::std::io::File::_isWritable(const ::std::string &_path)
  370. {
  371. bool writable{};
  372. if (ls::std::io::File::_exists(_path))
  373. {
  374. struct stat _stat
  375. {
  376. };
  377. if (stat(_path.c_str(), &_stat) == 0)
  378. {
  379. writable = (_stat.st_mode & (unsigned) S_IWRITE) != 0;
  380. }
  381. }
  382. return writable;
  383. }
  384. time_t ls::std::io::File::_lastModified(const ::std::string &_path)
  385. {
  386. time_t lastModifiedTimeStamp{};
  387. struct stat _stat
  388. {
  389. };
  390. if (stat(_path.c_str(), &_stat) == 0)
  391. {
  392. lastModifiedTimeStamp = _stat.st_mtime;
  393. }
  394. return lastModifiedTimeStamp;
  395. }
  396. ::std::list<::std::string> ls::std::io::File::_list(const ::std::string &_path)
  397. {
  398. ::std::list<::std::string> filesInDirectory{};
  399. #if defined(unix) || defined(__APPLE__)
  400. filesInDirectory = ls::std::io::File::_listUnix(_path, true);
  401. #endif
  402. #ifdef _WIN32
  403. filesInDirectory = ls::std::io::File::_listWindows(_path, true);
  404. #endif
  405. return filesInDirectory;
  406. }
  407. ::std::list<::std::string> ls::std::io::File::_listFiles(const ::std::string &_path)
  408. {
  409. ::std::list<::std::string> filesInDirectory{};
  410. #if defined(unix) || defined(__APPLE__)
  411. filesInDirectory = ls::std::io::File::_listUnix(_path, false);
  412. #endif
  413. #ifdef _WIN32
  414. filesInDirectory = ls::std::io::File::_listWindows(_path, false);
  415. #endif
  416. return filesInDirectory;
  417. }
  418. #if defined(unix) || defined(__APPLE__)
  419. ::std::list<::std::string> ls::std::io::File::_listUnix(const ::std::string &_path, bool withDirectories)
  420. {
  421. ::std::list<::std::string> filesInDirectory{};
  422. DIR *directory = opendir(_path.c_str());
  423. struct dirent *directoryEntity;
  424. ::std::string absolutePath{};
  425. while ((directoryEntity = readdir(directory)) != nullptr)
  426. {
  427. ls::std::io::File::_addToFileListUnix(_path, withDirectories, directoryEntity, filesInDirectory);
  428. }
  429. closedir(directory);
  430. return filesInDirectory;
  431. }
  432. #endif
  433. #ifdef _WIN32
  434. ::std::list<::std::string> ls::std::io::File::_listWindows(const ::std::string &_path, bool withDirectories)
  435. {
  436. ::std::list<::std::string> filesInDirectory{};
  437. WIN32_FIND_DATA data{};
  438. HANDLE hFind;
  439. ::std::string pattern{_path + ls::std::io::FilePathSeparator::get() + "*"};
  440. if ((hFind = FindFirstFile(pattern.c_str(), &data)) != INVALID_HANDLE_VALUE)
  441. {
  442. do
  443. {
  444. ls::std::io::File::_addToFileListWindows(_path, withDirectories, data, filesInDirectory);
  445. } while (FindNextFile(hFind, &data) != 0);
  446. FindClose(hFind);
  447. }
  448. return filesInDirectory;
  449. }
  450. #endif
  451. int ls::std::io::File::_mkdir(const ::std::string &_path)
  452. {
  453. int result;
  454. #ifdef _WIN32
  455. result = mkdir(_path.c_str());
  456. #endif
  457. #if defined(unix) || defined(__APPLE__)
  458. result = mkdir(_path.c_str(), 0777);
  459. #endif
  460. return result;
  461. }
  462. ::std::string ls::std::io::File::_normalizePath(::std::string _path)
  463. {
  464. _path = ls::std::io::File::_replaceWrongSeparator(_path);
  465. _path = ls::std::io::File::_reduceSeparators(_path);
  466. return _path;
  467. }
  468. ::std::string ls::std::io::File::_reduceSeparators(const ::std::string &_path)
  469. {
  470. static const char separator = {ls::std::io::FilePathSeparator::get()};
  471. ::std::string normalizedPath{};
  472. int index{};
  473. while (index < _path.size())
  474. {
  475. if (_path[index] == separator)
  476. {
  477. normalizedPath += _path[index];
  478. do
  479. {
  480. index++;
  481. } while (_path[index] == separator);
  482. }
  483. else
  484. {
  485. normalizedPath += _path[index];
  486. index++;
  487. }
  488. }
  489. return normalizedPath;
  490. }
  491. void ls::std::io::File::_remove(const ::std::string &_path)
  492. {
  493. #if defined(unix) || defined(__APPLE__)
  494. ls::std::io::File::_removeUnix(_path);
  495. #endif
  496. #ifdef _WIN32
  497. ls::std::io::File::_removeWindows(_path);
  498. #endif
  499. }
  500. #if defined(unix) || defined(__APPLE__)
  501. void ls::std::io::File::_removeUnix(const ::std::string &_path)
  502. {
  503. rmdir(_path.c_str());
  504. }
  505. #endif
  506. #ifdef _WIN32
  507. void ls::std::io::File::_removeWindows(const ::std::string &_path)
  508. {
  509. _rmdir(_path.c_str());
  510. }
  511. #endif
  512. bool ls::std::io::File::_renameTo(const ::std::string &_oldName, const ::std::string &_newName)
  513. {
  514. return ::std::rename(_oldName.c_str(), _newName.c_str()) == 0;
  515. }
  516. ::std::string ls::std::io::File::_replaceWrongSeparator(::std::string _path)
  517. {
  518. static const char unixSeparator = ls::std::io::FilePathSeparator::getUnixFilePathSeparator();
  519. static const char windowsSeparator = ls::std::io::FilePathSeparator::getWindowsFilePathSeparator();
  520. #if defined(unix) || defined(__APPLE__)
  521. ::std::replace(_path.begin(), _path.end(), windowsSeparator, unixSeparator);
  522. #endif
  523. #ifdef _WIN32
  524. ::std::replace(_path.begin(), _path.end(), unixSeparator, windowsSeparator);
  525. #endif
  526. return _path;
  527. }
  528. ::std::vector<::std::string> ls::std::io::File::_splitIntoSubDirectoryNames(const ::std::string &_path)
  529. {
  530. ::std::vector<::std::string> subDirectoryNames{};
  531. ::std::stringstream _stream{_path};
  532. ::std::string subDirectoryName{};
  533. const char separator = ls::std::io::FilePathSeparator::get();
  534. while (::std::getline(_stream, subDirectoryName, separator))
  535. {
  536. subDirectoryNames.push_back(subDirectoryName);
  537. }
  538. return subDirectoryNames;
  539. }