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

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