Open Source Tomb Raider Engine
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

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