Open Source Tomb Raider Engine
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Folder.cpp 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /*!
  2. * \file src/utils/Folder.cpp
  3. * \brief File-system walking utilities
  4. *
  5. * \author xythobuz
  6. */
  7. #include <algorithm>
  8. #include <cstring>
  9. #include <iostream>
  10. #include "global.h"
  11. #include <Log.h>
  12. #include "utils/filesystem.h"
  13. #include "utils/strings.h"
  14. #include "utils/Folder.h"
  15. File::File(std::string file) : path(file) {
  16. size_t pos = file.rfind('/', file.length() - 2);
  17. name = file.substr(pos + 1);
  18. std::transform(name.begin(), name.end(), name.begin(), ::tolower);
  19. }
  20. // ----------------------------------------------------------------------------
  21. #if defined(HAVE_DIRENT_H) && defined(HAVE_OPENDIR) && defined(HAVE_READDIR_R) && defined(HAVE_CLOSEDIR) && defined(HAVE_DT_DIR)
  22. #include <dirent.h>
  23. #define USE_DIRENT
  24. #elif defined (_WIN32)
  25. #include <windows.h>
  26. #define USE_FINDFILE
  27. #else
  28. #error No support for recursive folder traversal
  29. #endif
  30. Folder::Folder(std::string folder, bool listDotFiles) {
  31. if (((folder.length() == 0) || (folder.compare(".") == 0))
  32. #ifdef _WIN32
  33. || ((folder.compare(1, 2, std::string(":\\")) != 0) && (folder.at(0) != '~'))
  34. #else
  35. || ((folder.at(0) != '/') && (folder.at(0) != '~'))
  36. #endif
  37. ) {
  38. // Prepend current working directory
  39. path = getCurrentWorkingDirectory();
  40. if (folder.length() > 1)
  41. path += folder.substr(1);
  42. } else if (folder.at(0) == '~') {
  43. // Prepend home directory
  44. path = getHomeDirectory();
  45. std::cout << "Home: " << path << std::endl;
  46. if (folder.length() > 1)
  47. path += folder.substr(1);
  48. } else {
  49. path = folder;
  50. }
  51. // Find all '\\' replace with '/'
  52. size_t pos = path.find('\\');
  53. while (pos != std::string::npos) {
  54. path.at(pos) = '/';
  55. pos = path.find('\\');
  56. }
  57. size_t last = 0;
  58. if (path.length() > 1)
  59. last = path.rfind('/', path.length() - 2);
  60. name = path.substr(last + 1);
  61. if (name.back() == '/')
  62. name.erase(name.length() - 1);
  63. std::transform(name.begin(), name.end(), name.begin(), ::tolower);
  64. if (path.back() != '/')
  65. path.append(1, '/');
  66. hasListed = false;
  67. listDot = listDotFiles;
  68. }
  69. unsigned long Folder::fileCount() {
  70. createFolderItems();
  71. return files.size();
  72. }
  73. File& Folder::getFile(unsigned long i) {
  74. createFolderItems();
  75. orAssert(i < files.size());
  76. return files.at(i);
  77. }
  78. unsigned long Folder::folderCount() {
  79. createFolderItems();
  80. return folders.size();
  81. }
  82. Folder& Folder::getFolder(unsigned long i) {
  83. createFolderItems();
  84. orAssert(i < folders.size());
  85. return folders.at(i);
  86. }
  87. Folder Folder::getParent() {
  88. size_t last = path.rfind('/', path.length() - 2);
  89. std::string parent = path.substr(0, last);
  90. if (parent.length() == 0)
  91. parent = "/";
  92. return Folder(parent, listDot);
  93. }
  94. void Folder::executeRemoveFiles(std::function<bool (File& f)> func) {
  95. createFolderItems();
  96. for (unsigned long i = 0; i < fileCount(); i++) {
  97. if (func(getFile(i))) {
  98. files.erase(files.begin() + (long)i--);
  99. }
  100. }
  101. }
  102. void Folder::createFolderItems() {
  103. if (hasListed)
  104. return;
  105. std::vector<std::string> foundFiles, foundFolders;
  106. if (readFolderItems(foundFiles, foundFolders) != 0) {
  107. Log::get(LOG_ERROR) << "Could not open folder " << name << Log::endl;
  108. }
  109. if (!listDot) {
  110. std::vector<std::string>::iterator it = foundFiles.begin();
  111. while (it != foundFiles.end()) {
  112. size_t pos = it->rfind('/', it->length() - 2);
  113. if (it->at(pos + 1) == '.')
  114. it = foundFiles.erase(it);
  115. else
  116. ++it;
  117. }
  118. it = foundFolders.begin();
  119. while (it != foundFolders.end()) {
  120. size_t pos = it->rfind('/', it->length() - 2);
  121. if (it->at(pos + 1) == '.')
  122. it = foundFolders.erase(it);
  123. else
  124. ++it;
  125. }
  126. }
  127. std::sort(foundFiles.begin(), foundFiles.end());
  128. std::sort(foundFolders.begin(), foundFolders.end());
  129. for (unsigned long i = 0; i < foundFiles.size(); i++)
  130. files.emplace_back(File(foundFiles.at(i)));
  131. for (unsigned long i = 0; i < foundFolders.size(); i++)
  132. folders.emplace_back(Folder(foundFolders.at(i)));
  133. hasListed = true;
  134. }
  135. #ifdef USE_DIRENT
  136. int Folder::readFolderItems(std::vector<std::string>& foundFiles,
  137. std::vector<std::string>& foundFolders) {
  138. struct dirent entry;
  139. struct dirent* ep = nullptr;
  140. DIR* pakDir;
  141. pakDir = opendir(path.c_str());
  142. if (pakDir != nullptr) {
  143. readdir_r(pakDir, &entry, &ep);
  144. while (ep != nullptr) {
  145. if ((strcmp(".", ep->d_name) != 0)
  146. && (strcmp("..", ep->d_name) != 0)) {
  147. std::string tmp(path);
  148. if (tmp.back() != '/')
  149. tmp += '/';
  150. tmp += ep->d_name;
  151. if (ep->d_type == DT_DIR) {
  152. if (tmp.back() != '/')
  153. tmp += '/';
  154. foundFolders.push_back(std::string(tmp));
  155. } else {
  156. foundFiles.push_back(std::string(tmp));
  157. }
  158. }
  159. readdir_r(pakDir, &entry, &ep);
  160. }
  161. closedir(pakDir);
  162. } else {
  163. return 1;
  164. }
  165. return 0;
  166. }
  167. #elif defined(USE_FINDFILE)
  168. int Folder::readFolderItems(std::vector<std::string>& foundFiles,
  169. std::vector<std::string>& foundFolders) {
  170. std::string tmp(path);
  171. tmp += "/*";
  172. WIN32_FIND_DATA fd;
  173. HANDLE hFind = FindFirstFile(tmp.c_str(), &fd);
  174. if (hFind == nullptr)
  175. return 1;
  176. do {
  177. std::string s(path);
  178. s = s + "/" + fd.cFileName;
  179. if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  180. foundFolders.push_back(s);
  181. else
  182. foundFiles.push_back(s);
  183. } while (FindNextFile(hFind, &fd) != 0);
  184. FindClose(hFind);
  185. return 0;
  186. }
  187. #endif
  188. void Folder::findFilesEndingWith(std::vector<File>& found, std::string end, bool casesensitive) {
  189. createFolderItems();
  190. for (auto& f : files) {
  191. if (stringEndsWith(f.getName(), end, casesensitive))
  192. found.push_back(f);
  193. }
  194. }