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

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