MinitScript  0.9.31 PRE-BETA
FileSystem.cpp
Go to the documentation of this file.
2 
3 #include <algorithm>
4 #include <array>
5 #include <filesystem>
6 #include <fstream>
7 #include <iostream>
8 #include <sstream>
9 #include <string>
10 #include <vector>
11 
17 
18 using std::array;
19 using std::getline;
20 using std::ifstream;
21 using std::ios;
22 using std::ofstream;
23 using std::sort;
24 using std::string;
25 using std::stringstream;
26 using std::to_string;
27 using std::vector;
28 
30 
35 
36 const string FileSystem::composeURI(const string& pathName, const string& fileName) {
37  return pathName + "/" + fileName;
38 }
39 
40 void FileSystem::list(const string& pathName, vector<string>& files, FileNameFilter* filter, bool addDrives)
41 {
42  auto _pathName = pathName;
43  if (StringTools::endsWith(_pathName, "/") == false) _pathName+= "/";
44 
45  try {
46  for (const auto& entry: std::filesystem::directory_iterator(std::filesystem::path((const char8_t*)_pathName.c_str()))) {
47  auto u8FileName = entry.path().filename().u8string();
48  string fileName(u8FileName.size(), 0);
49  for (auto i = 0; i < u8FileName.size(); i++) fileName[i] = u8FileName[i];
50  try {
51  if (filter != nullptr && filter->accept(pathName, fileName) == false) continue;
52  } catch (Exception& exception) {
53  Console::printLine("FileSystem::list(): Filter::accept(): " + pathName + "/" + fileName + ": " + string(exception.what()));
54  continue;
55  }
56  files.push_back(fileName);
57  }
58  } catch (Exception& exception) {
59  throw FileSystemException("Unable to list path: " + pathName + ": " + string(exception.what()));
60  }
61 
62  //
63  sort(files.begin(), files.end());
64 
65  //
66  if (isDrive(_pathName) == false && _pathName.empty() == false && _pathName != "/") {
67  if (filter == nullptr || filter->accept(pathName, "..") == true) files.insert(files.begin(), "..");
68  }
69 
70  #if defined(_WIN32)
71  if (addDrives == true) {
72  for (char drive = 'A'; drive <= 'Z'; drive++) {
73  string fileName;
74  fileName+= drive;
75  fileName+= ":";
76  try {
77  if (exists(fileName + "/") == true) files.insert(files.begin() + (drive - 'C'), fileName);
78  } catch (Exception& exception) {
79  Console::printLine("FileSystem::list(): fileExists(): " + pathName + "/" + fileName + ": " + string(exception.what()));
80  }
81  }
82  }
83  #endif
84 }
85 
86 bool FileSystem::isPath(const string& pathName) {
87  try {
88  auto status = std::filesystem::status(std::filesystem::path((const char8_t*)pathName.c_str()));
89  return std::filesystem::is_directory(status);
90  } catch (Exception& exception) {
91  throw FileSystemException("Unable to check if path: " + pathName + ": " + string(exception.what()));
92  }
93  //
94  return false;
95 }
96 
97 bool FileSystem::isDrive(const string& pathName) {
98  return StringTools::regexMatch(pathName, "^[a-zA-Z]{1}\\:.*$");
99 }
100 
101 bool FileSystem::exists(const string& uri) {
102  try {
103  return std::filesystem::exists(std::filesystem::path((const char8_t*)uri.c_str()));
104  } catch (Exception& exception) {
105  throw FileSystemException("Unable to check if file exists: " + uri + ": " + string(exception.what()));
106  }
107  //
108  return false;
109 }
110 
111 uint64_t FileSystem::getFileSize(const string& pathName, const string& fileName) {
112  try {
113  return std::filesystem::file_size(std::filesystem::path((const char8_t*)composeURI(pathName, fileName).c_str()));
114  } catch (Exception& exception) {
115  throw FileSystemException("Unable to determine file size: " + fileName + ": " + string(exception.what()));
116  }
117  //
118  return false;
119 }
120 
121 const string FileSystem::getContentAsString(const string& pathName, const string& fileName) {
122  ifstream ifs(std::filesystem::path((const char8_t*)composeURI(pathName, fileName).c_str()));
123  if (ifs.is_open() == false) {
124  throw FileSystemException("Unable to open file for reading(" + to_string(errno) + "): " + pathName + "/" + fileName);
125  }
126  stringstream stringStream;
127  stringStream << ifs.rdbuf();
128  ifs.close();
129  return (stringStream.str());
130 }
131 
132 void FileSystem::setContentFromString(const string& pathName, const string& fileName, const string& content) {
133  ofstream ofs(std::filesystem::path((const char8_t*)composeURI(pathName, fileName).c_str()));
134  if (ofs.is_open() == false) {
135  throw FileSystemException("Unable to open file for writing(" + to_string(errno) + "): " + pathName + "/" + fileName);
136  }
137  ofs << (content);
138  ofs.close();
139  return;
140 }
141 
142 void FileSystem::getContent(const string& pathName, const string& fileName, vector<uint8_t>& content)
143 {
144  ifstream ifs(std::filesystem::path((const char8_t*)composeURI(pathName, fileName).c_str()), ifstream::binary);
145  if (ifs.is_open() == false) {
146  throw FileSystemException("Unable to open file for reading(" + to_string(errno) + "): " + pathName + "/" + fileName);
147  }
148  ifs.seekg( 0, ios::end );
149  size_t size = ifs.tellg();
150  content.resize(size);
151  ifs.seekg(0, ios::beg);
152  ifs.read((char*)content.data(), size);
153  ifs.close();
154 }
155 
156 void FileSystem::setContent(const string& pathName, const string& fileName, const vector<uint8_t>& content) {
157  ofstream ofs(std::filesystem::path((const char8_t*)composeURI(pathName, fileName).c_str()), ofstream::binary);
158  if (ofs.is_open() == false) {
159  throw FileSystemException("Unable to open file for writing(" + to_string(errno) + "): " + pathName + "/" + fileName);
160  }
161  ofs.write((char*)content.data(), content.size());
162  ofs.close();
163 }
164 
165 void FileSystem::getContentAsStringArray(const string& pathName, const string& fileName, vector<string>& content)
166 {
167  ifstream ifs(std::filesystem::path((const char8_t*)composeURI(pathName, fileName).c_str()));
168  if(ifs.is_open() == false) {
169  throw FileSystemException("Unable to open file for reading(" + to_string(errno) + "): " + pathName + "/" + fileName);
170  }
171 
172  string line;
173  while (getline(ifs, line)) {
174  content.push_back(StringTools::replace(line, "\r", ""));
175  }
176 
177  ifs.close();
178 }
179 
180 void FileSystem::setContentFromStringArray(const string& pathName, const string& fileName, const vector<string>& content)
181 {
182  ofstream ofs(std::filesystem::path((const char8_t*)composeURI(pathName, fileName).c_str()), ofstream::binary);
183  if(ofs.is_open() == false) {
184  throw FileSystemException("Unable to open file for writing(" + to_string(errno) + "): " + pathName + "/" + fileName);
185  }
186 
187  for (auto i = 0; i < content.size(); i++) {
188  ofs << (content.at(i)) << "\n";
189  }
190 
191  ofs.close();
192  return;
193 }
194 
195 const string FileSystem::getCanonicalURI(const string& pathName, const string& fileName) {
196  string unixPathName = StringTools::replace(pathName, "\\", "/");
197  string unixFileName = StringTools::replace(fileName, "\\", "/");
198 
199  //
200  auto pathString = composeURI(unixPathName, unixFileName);
201 
202  // separate into path components
203  vector<string> pathComponents;
204  StringTokenizer t;
205  t.tokenize(pathString, "/");
206  while (t.hasMoreTokens()) {
207  pathComponents.push_back(t.nextToken());
208  }
209 
210  // process path components
211  for (auto i = 0; i < pathComponents.size(); i++) {
212  auto pathComponent = pathComponents[i];
213  if (pathComponent == ".") {
214  pathComponents[i].clear();
215  } else
216  if (pathComponent == "..") {
217  pathComponents[i].clear();
218  int j = i - 1;
219  for (int pathComponentReplaced = 0; pathComponentReplaced < 1 && j >= 0; ) {
220  if (pathComponents[j].empty() == false) {
221  pathComponents[j].clear();
222  pathComponentReplaced++;
223  }
224  j--;
225  }
226  }
227  }
228 
229  // process path components
230  string canonicalPath = "";
231  bool slash = StringTools::startsWith(pathString, "/");
232  for (auto i = 0; i < pathComponents.size(); i++) {
233  auto pathComponent = pathComponents[i];
234  if (pathComponent.empty() == true) {
235  // no op
236  } else {
237  canonicalPath = canonicalPath + (slash == true?"/":"") + pathComponent;
238  slash = true;
239  }
240  }
241 
242  // add cwd if required
243  auto canonicalPathString = canonicalPath.empty() == true?"/":canonicalPath;
244  /*
245  if (canonicalPathString.length() == 0 ||
246  (StringTools::startsWith(canonicalPathString, "/") == false &&
247  StringTools::regexMatch(canonicalPathString, "^[a-zA-Z]\\:.*$") == false)) {
248  canonicalPathString = getCurrentWorkingPathName() + "/" + canonicalPathString;
249  }
250  */
251 
252  //
253  return canonicalPathString;
254 }
255 
257  try {
258  auto u8Cwd = std::filesystem::current_path().u8string();
259  string cwd(u8Cwd.size(), 0);
260  for (auto i = 0; i < u8Cwd.size(); i++) cwd[i] = u8Cwd[i];
261  return cwd;
262  } catch (Exception& exception) {
263  throw FileSystemException("Unable to get current path: " + string(exception.what()));
264  }
265  //
266  return string(".");
267 }
268 
269 void FileSystem::changePath(const string& pathName) {
270  try {
271  return std::filesystem::current_path(std::filesystem::path((const char8_t*)pathName.c_str()));
272  } catch (Exception& exception) {
273  throw FileSystemException("Unable to change path: " + pathName + ": " + string(exception.what()));
274  }
275 }
276 
277 const string FileSystem::getPathName(const string& uri) {
278  auto unixFileName = StringTools::replace(uri, '\\', '/');
279  auto lastPathSeparator = StringTools::lastIndexOf(unixFileName, '/');
280  if (lastPathSeparator == -1) return ".";
281  return StringTools::substring(unixFileName, 0, lastPathSeparator);
282 }
283 
284 const string FileSystem::getFileName(const string& uri) {
285  auto unixFileName = StringTools::replace(uri, '\\', '/');
286  auto lastPathSeparator = StringTools::lastIndexOf(unixFileName, '/');
287  if (lastPathSeparator == -1) return uri;
288  return StringTools::substring(unixFileName, lastPathSeparator + 1, unixFileName.length());
289 }
290 
291 const string FileSystem::removeFileExtension(const string& fileName) {
292  auto idx = fileName.rfind('.');
293  if (idx == string::npos) {
294  return fileName;
295  } else {
296  return fileName.substr(0, idx);
297  }
298 }
299 
300 void FileSystem::createPath(const string& pathName) {
301  try {
302  if (std::filesystem::create_directory(std::filesystem::path((const char8_t*)pathName.c_str())) == false) {
303  throw FileSystemException("Unable to create path: " + pathName);
304  }
305  } catch (Exception& exception) {
306  throw FileSystemException("Unable to create path: " + pathName + ": " + string(exception.what()));
307  }
308 }
309 
310 void FileSystem::removePath(const string& pathName, bool recursive) {
311  try {
312  if (recursive == false) {
313  if (std::filesystem::remove(std::filesystem::path((const char8_t*)pathName.c_str())) == false) {
314  throw FileSystemException("Unable to remove path: " + pathName);
315  }
316  } else {
317  if (std::filesystem::remove_all(std::filesystem::path((const char8_t*)pathName.c_str())) == false) {
318  throw FileSystemException("Unable to remove path recursively: " + pathName);
319  }
320  }
321  } catch (Exception& exception) {
322  throw FileSystemException("Unable to remove path: " + pathName + ": " + string(exception.what()));
323  }
324 }
325 
326 void FileSystem::removeFile(const string& pathName, const string& fileName) {
327  try {
328  if (std::filesystem::remove(std::filesystem::path((const char8_t*)composeURI(pathName, fileName).c_str())) == false) {
329  throw FileSystemException("Unable to remove file: " + pathName + "/" + fileName);
330  }
331  } catch (Exception& exception) {
332  throw FileSystemException("Unable to remove file: " + pathName + "/" + fileName + ": " + string(exception.what()));
333  }
334 }
335 
336 void FileSystem::rename(const string& fileNameFrom, const string& fileNameTo) {
337  try {
338  std::filesystem::rename(std::filesystem::path((const char8_t*)fileNameFrom.c_str()), std::filesystem::path((const char8_t*)fileNameTo.c_str()));
339  } catch (Exception& exception) {
340  throw FileSystemException("Unable to rename file: " + fileNameFrom + " -> " + fileNameTo + ": " + string(exception.what()));
341  }
342 }
static const string removeFileExtension(const string &fileName)
Remove file extension, e.g.
Definition: FileSystem.cpp:291
static bool isDrive(const string &uri)
Check if file is a drive (applies to Microsoft Windows only)
Definition: FileSystem.cpp:97
static void setContentFromString(const string &pathName, const string &fileName, const string &content)
Set content from string.
Definition: FileSystem.cpp:132
static const string composeURI(const string &pathName, const string &fileName)
Compose URI from path name and file name.
Definition: FileSystem.cpp:36
static const string getPathName(const string &uri)
Get path name.
Definition: FileSystem.cpp:277
static const string getCanonicalURI(const string &pathName, const string &fileName)
Get canonical URI from given path name and file name.
Definition: FileSystem.cpp:195
static void createPath(const string &pathName)
Create path.
Definition: FileSystem.cpp:300
static void list(const string &pathName, vector< string > &files, FileNameFilter *filter=nullptr, bool addDrives=false)
List files for given path and filter by a file name filter if not null.
Definition: FileSystem.cpp:40
static void changePath(const string &pathName)
Change path.
Definition: FileSystem.cpp:269
static void removePath(const string &pathName, bool recursive)
Remove path.
Definition: FileSystem.cpp:310
static void setContent(const string &pathName, const string &fileName, const vector< uint8_t > &content)
Set file content.
Definition: FileSystem.cpp:156
static void getContent(const string &pathName, const string &fileName, vector< uint8_t > &content)
Get file content.
Definition: FileSystem.cpp:142
static void setContentFromStringArray(const string &pathName, const string &fileName, const vector< string > &content)
Set file content as string array.
Definition: FileSystem.cpp:180
static void removeFile(const string &pathName, const string &fileName)
Remove file.
Definition: FileSystem.cpp:326
static uint64_t getFileSize(const string &pathName, const string &fileName)
Return file size of given file.
Definition: FileSystem.cpp:111
static void getContentAsStringArray(const string &pathName, const string &fileName, vector< string > &content)
Get file content as string array.
Definition: FileSystem.cpp:165
static const string getFileName(const string &uri)
Get file name.
Definition: FileSystem.cpp:284
static bool isPath(const string &uri)
Check if file is a path.
Definition: FileSystem.cpp:86
static bool exists(const string &uri)
Check if file exists.
Definition: FileSystem.cpp:101
static const string getCurrentWorkingPathName()
Get current working path name.
Definition: FileSystem.cpp:256
static const string getContentAsString(const string &pathName, const string &fileName)
Get content as string.
Definition: FileSystem.cpp:121
static void rename(const string &fileNameFrom, const string &fileNameTo)
Rename file.
Definition: FileSystem.cpp:336
void tokenize(const string &str, const string &delimiters, bool emptyTokens=false)
Tokenize.
std::exception Exception
Exception base class.
Definition: Exception.h:18
File system file name filter interface.
Definition: FileSystem.h:44
virtual bool accept(const string &path, const string &file)=0
Accept a file.