OpenRaider  0.1.4-dev
Open Source Tomb Raider Game Engine implementation
Folder.cpp
Go to the documentation of this file.
1 
8 #include <algorithm>
9 #include <iostream>
10 
11 #include "global.h"
12 #include <Log.h>
13 #include "utils/filesystem.h"
14 #include "utils/strings.h"
15 #include "utils/Folder.h"
16 
17 File::File(std::string file) : path(file) {
18  size_t pos = file.rfind('/', file.length() - 2);
19  name = file.substr(pos + 1);
20  std::transform(name.begin(), name.end(), name.begin(), ::tolower);
21 }
22 
23 // ----------------------------------------------------------------------------
24 
25 #if defined(HAVE_DIRENT_H) && defined(HAVE_OPENDIR) && defined(HAVE_READDIR_R) && defined(HAVE_CLOSEDIR) && defined(HAVE_DT_DIR)
26 #include <dirent.h>
27 #define USE_DIRENT
28 #elif defined (_WIN32)
29 #include <windows.h>
30 #define USE_FINDFILE
31 #else
32 #error No support for recursive folder traversal
33 #endif
34 
35 Folder::Folder(std::string folder, bool listDotFiles) {
36  if (((folder.length() == 0) || (folder.compare(".") == 0))
37 #ifdef _WIN32
38  || ((folder.compare(1, 2, std::string(":\\")) != 0) && (folder.at(0) != '~'))
39 #else
40  || ((folder.at(0) != '/') && (folder.at(0) != '~'))
41 #endif
42  ) {
43  // Prepend current working directory
45  if (folder.length() > 1)
46  path += folder.substr(1);
47  } else if (folder.at(0) == '~') {
48  // Prepend home directory
50  std::cout << "Home: " << path << std::endl;
51  if (folder.length() > 1)
52  path += folder.substr(1);
53  } else {
54  path = folder;
55  }
56 
57  // Find all '\\' replace with '/'
58  size_t pos = path.find('\\');
59  while (pos != std::string::npos) {
60  path.at(pos) = '/';
61  pos = path.find('\\');
62  }
63 
64  size_t last = 0;
65  if (path.length() > 1)
66  last = path.rfind('/', path.length() - 2);
67  name = path.substr(last + 1);
68  if (name.back() == '/')
69  name.erase(name.length() - 1);
70 
71  std::transform(name.begin(), name.end(), name.begin(), ::tolower);
72 
73  if (path.back() != '/')
74  path.append(1, '/');
75 
76  hasListed = false;
77  listDot = listDotFiles;
78 }
79 
80 unsigned long Folder::fileCount() {
82  return files.size();
83 }
84 
85 File& Folder::getFile(unsigned long i) {
87  assert(i < files.size());
88  return files.at(i);
89 }
90 
91 unsigned long Folder::folderCount() {
93  return folders.size();
94 }
95 
96 Folder& Folder::getFolder(unsigned long i) {
98  assert(i < folders.size());
99  return folders.at(i);
100 }
101 
103  size_t last = path.rfind('/', path.length() - 2);
104  std::string parent = path.substr(0, last);
105  if (parent.length() == 0)
106  parent = "/";
107  return Folder(parent, listDot);
108 }
109 
110 void Folder::executeRemoveFiles(std::function<bool (File& f)> func) {
112  for (unsigned long i = 0; i < fileCount(); i++) {
113  if (func(getFile(i))) {
114  files.erase(files.begin() + (long)i--);
115  }
116  }
117 }
118 
120  if (hasListed)
121  return;
122 
123  std::vector<std::string> foundFiles, foundFolders;
124  if (readFolderItems(foundFiles, foundFolders) != 0) {
125  Log::get(LOG_ERROR) << "Could not open folder " << name << Log::endl;
126  }
127 
128  if (!listDot) {
129  std::vector<std::string>::iterator it = foundFiles.begin();
130  while (it != foundFiles.end()) {
131  size_t pos = it->rfind('/', it->length() - 2);
132  if (it->at(pos + 1) == '.')
133  it = foundFiles.erase(it);
134  else
135  ++it;
136  }
137 
138  it = foundFolders.begin();
139  while (it != foundFolders.end()) {
140  size_t pos = it->rfind('/', it->length() - 2);
141  if (it->at(pos + 1) == '.')
142  it = foundFolders.erase(it);
143  else
144  ++it;
145  }
146  }
147 
148  std::sort(foundFiles.begin(), foundFiles.end());
149  std::sort(foundFolders.begin(), foundFolders.end());
150 
151  for (unsigned long i = 0; i < foundFiles.size(); i++)
152  files.emplace_back(File(foundFiles.at(i)));
153 
154  for (unsigned long i = 0; i < foundFolders.size(); i++)
155  folders.emplace_back(Folder(foundFolders.at(i)));
156 
157  hasListed = true;
158 }
159 
160 #ifdef USE_DIRENT
161 
162 int Folder::readFolderItems(std::vector<std::string>& foundFiles,
163  std::vector<std::string>& foundFolders) {
164  struct dirent entry;
165  struct dirent* ep = nullptr;
166  DIR* pakDir;
167 
168  pakDir = opendir(path.c_str());
169  if (pakDir != nullptr) {
170  readdir_r(pakDir, &entry, &ep);
171  while (ep != nullptr) {
172  if ((strcmp(".", ep->d_name) != 0)
173  && (strcmp("..", ep->d_name) != 0)) {
174  std::string tmp(path);
175  if (tmp.back() != '/')
176  tmp += '/';
177  tmp += ep->d_name;
178  if (ep->d_type == DT_DIR) {
179  if (tmp.back() != '/')
180  tmp += '/';
181  foundFolders.push_back(std::string(tmp));
182  } else {
183  foundFiles.push_back(std::string(tmp));
184  }
185  }
186  readdir_r(pakDir, &entry, &ep);
187  }
188  closedir(pakDir);
189  } else {
190  return 1;
191  }
192 
193  return 0;
194 }
195 
196 #elif defined(USE_FINDFILE)
197 
198 int Folder::readFolderItems(std::vector<std::string>& foundFiles,
199  std::vector<std::string>& foundFolders) {
200  std::string tmp(path);
201  tmp += "/*";
202 
203  WIN32_FIND_DATA fd;
204  HANDLE hFind = FindFirstFile(tmp.c_str(), &fd);
205  if (hFind == nullptr)
206  return 1;
207 
208  do {
209  std::string s(path);
210  s = s + "/" + fd.cFileName;
211  if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
212  foundFolders.push_back(s);
213  else
214  foundFiles.push_back(s);
215  } while (FindNextFile(hFind, &fd) != 0);
216 
217  FindClose(hFind);
218  return 0;
219 }
220 
221 #endif
222 
223 void Folder::findFilesEndingWith(std::vector<File>& found, std::string end, bool casesensitive) {
225  for (auto& f : files) {
226  if (stringEndsWith(f.getName(), end, casesensitive))
227  found.push_back(f);
228  }
229 }
230 
std::string name
Only last part of path.
Definition: Folder.h:59
Folder & getFolder(unsigned long i)
Definition: Folder.cpp:96
String handling utilities.
Definition: Folder.h:16
unsigned long folderCount()
Definition: Folder.cpp:91
bool listDot
Definition: Folder.h:63
Folder getParent()
Definition: Folder.cpp:102
Included everywhere.
Folder(std::string folder, bool listDotFiles=false)
Definition: Folder.cpp:35
static LogLevel & get(int level)
Definition: Log.cpp:14
std::vector< File > files
Definition: Folder.h:65
Global Logging Utility.
unsigned long fileCount()
Definition: Folder.cpp:80
bool stringEndsWith(std::string s, std::string suffix, bool casesensitive=false)
Definition: strings.cpp:32
#define assert(x)
Definition: global.h:124
std::vector< Folder > folders
Definition: Folder.h:66
file-system utilities
std::string getCurrentWorkingDirectory()
Definition: filesystem.cpp:24
Recursive file-system walking utilities.
bool hasListed
Definition: Folder.h:62
std::string path
Full path, with name and '/' at end.
Definition: Folder.h:60
static const char endl
Definition: Log.h:35
void executeRemoveFiles(std::function< bool(File &f)> func)
Definition: Folder.cpp:110
File & getFile(unsigned long i)
Definition: Folder.cpp:85
File(std::string file)
Definition: Folder.cpp:17
void createFolderItems()
Definition: Folder.cpp:119
#define LOG_ERROR
Definition: Log.h:19
Definition: Folder.h:28
void findFilesEndingWith(std::vector< File > &found, std::string end, bool casesensitive=false)
Definition: Folder.cpp:223
std::string name
Definition: Folder.h:24
std::string getHomeDirectory()
Definition: filesystem.cpp:39
int readFolderItems(std::vector< std::string > &foundFiles, std::vector< std::string > &foundFolders)