26 using std::stringstream;
38 StandardFileSystem::StandardFileSystem()
47 return pathName +
"/" + fileName;
52 auto _pathName = pathName;
53 if (StringTools::endsWith(_pathName,
"/") ==
false) _pathName+=
"/";
56 for (
const auto& entry: std::filesystem::directory_iterator(std::filesystem::u8path(_pathName))) {
57 auto u8FileName = entry.path().filename().u8string();
58 string fileName(u8FileName.size(), 0);
59 for (
auto i = 0; i < u8FileName.size(); i++) fileName[i] = u8FileName[i];
61 if (filter !=
nullptr && filter->
accept(pathName, fileName) ==
false)
continue;
63 Console::println(
"StandardFileSystem::list(): Filter::accept(): " + pathName +
"/" + fileName +
": " +
string(exception.what()));
66 files.push_back(fileName);
69 throw FileSystemException(
"Unable to list path: " + pathName +
": " +
string(exception.what()));
73 sort(files.begin(), files.end());
76 if (
isDrive(_pathName) ==
false && _pathName.empty() ==
false && _pathName !=
"/") {
77 if (filter ==
nullptr || filter->
accept(pathName,
"..") ==
true) files.insert(files.begin(),
"..");
81 if (addDrives ==
true) {
82 for (
char drive =
'A'; drive <=
'Z'; drive++) {
87 if (
exists(fileName +
"/") ==
true) files.insert(files.begin() + (drive -
'C'), fileName);
89 Console::println(
"StandardFileSystem::list(): fileExists(): " + pathName +
"/" + fileName +
": " +
string(exception.what()));
98 auto status = std::filesystem::status(std::filesystem::u8path(pathName));
99 return std::filesystem::is_directory(status);
101 throw FileSystemException(
"Unable to check if path: " + pathName +
": " +
string(exception.what()));
108 return StringTools::regexMatch(pathName,
"^[a-zA-Z]{1}\\:.*$");
113 return std::filesystem::exists(std::filesystem::u8path(uri));
115 throw FileSystemException(
"Unable to check if file exists: " + uri +
": " +
string(exception.what()));
123 auto permissions = std::filesystem::status(std::filesystem::u8path(pathName +
"/" + fileName)).permissions();
125 (permissions & std::filesystem::perms::owner_exec) == std::filesystem::perms::owner_exec ||
126 (permissions & std::filesystem::perms::group_exec) == std::filesystem::perms::group_exec ||
127 (permissions & std::filesystem::perms::others_exec) == std::filesystem::perms::others_exec;
129 throw FileSystemException(
"Unable to determine permissions: " + pathName +
"/" + fileName +
": " +
string(exception.what()));
137 std::filesystem::permissions(
138 std::filesystem::u8path(pathName +
"/" + fileName),
139 std::filesystem::perms::owner_exec,
140 std::filesystem::perm_options::add
143 throw FileSystemException(
"Unable to set executable permissions: " + pathName +
"/" + fileName +
": " +
string(exception.what()));
149 return std::filesystem::file_size(std::filesystem::u8path(pathName +
"/" + fileName));
151 throw FileSystemException(
"Unable to determine file size: " + fileName +
": " +
string(exception.what()));
158 ifstream ifs(std::filesystem::u8path(
composeURI(pathName, fileName)));
159 if (ifs.is_open() ==
false) {
160 throw FileSystemException(
"Unable to open file for reading(" + to_string(errno) +
"): " + pathName +
"/" + fileName);
162 stringstream stringStream;
163 stringStream << ifs.rdbuf();
165 return (stringStream.str());
169 ofstream ofs(std::filesystem::u8path(
composeURI(pathName, fileName)));
170 if (ofs.is_open() ==
false) {
171 throw FileSystemException(
"Unable to open file for writing(" + to_string(errno) +
"): " + pathName +
"/" + fileName);
180 ifstream ifs(std::filesystem::u8path(
composeURI(pathName, fileName)), ifstream::binary);
181 if (ifs.is_open() ==
false) {
182 throw FileSystemException(
"Unable to open file for reading(" + to_string(errno) +
"): " + pathName +
"/" + fileName);
184 ifs.seekg( 0, ios::end );
185 size_t size = ifs.tellg();
186 content.resize(size);
187 ifs.seekg(0, ios::beg);
188 ifs.read((
char*)content.data(), size);
193 ofstream ofs(std::filesystem::u8path(
composeURI(pathName, fileName)), ofstream::binary);
194 if (ofs.is_open() ==
false) {
195 throw FileSystemException(
"Unable to open file for writing(" + to_string(errno) +
"): " + pathName +
"/" + fileName);
197 ofs.write((
char*)content.data(), content.size());
203 ifstream ifs(std::filesystem::u8path(
composeURI(pathName, fileName)));
204 if(ifs.is_open() ==
false) {
205 throw FileSystemException(
"Unable to open file for reading(" + to_string(errno) +
"): " + pathName +
"/" + fileName);
209 while (getline(ifs, line)) {
210 content.push_back(StringTools::replace(line,
"\r",
""));
218 ofstream ofs(std::filesystem::u8path(
composeURI(pathName, fileName)), ofstream::binary);
219 if(ofs.is_open() ==
false) {
220 throw FileSystemException(
"Unable to open file for writing(" + to_string(errno) +
"): " + pathName +
"/" + fileName);
223 for (
auto i = 0; i < content.size(); i++) {
224 ofs << (content.at(i)) <<
"\n";
232 string unixPathName = StringTools::replace(pathName,
"\\",
"/");
233 string unixFileName = StringTools::replace(fileName,
"\\",
"/");
236 auto pathString =
composeURI(unixPathName, unixFileName);
239 vector<string> pathComponents;
247 for (
auto i = 0; i < pathComponents.size(); i++) {
248 auto pathComponent = pathComponents[i];
249 if (pathComponent ==
".") {
250 pathComponents[i].clear();
252 if (pathComponent ==
"..") {
253 pathComponents[i].clear();
255 for (
int pathComponentReplaced = 0; pathComponentReplaced < 1 && j >= 0; ) {
256 if (pathComponents[j].empty() ==
false) {
257 pathComponents[j].clear();
258 pathComponentReplaced++;
266 string canonicalPath =
"";
267 bool slash = StringTools::startsWith(pathString,
"/");
268 for (
auto i = 0; i < pathComponents.size(); i++) {
269 auto pathComponent = pathComponents[i];
270 if (pathComponent.empty() ==
true) {
273 canonicalPath = canonicalPath + (slash ==
true?
"/":
"") + pathComponent;
279 auto canonicalPathString = canonicalPath.empty() ==
true?
"/":canonicalPath;
289 return canonicalPathString;
294 auto u8Cwd = std::filesystem::current_path().u8string();
295 string cwd(u8Cwd.size(), 0);
296 for (
auto i = 0; i < u8Cwd.size(); i++) cwd[i] = u8Cwd[i];
307 return std::filesystem::current_path(std::filesystem::u8path(pathName));
309 throw FileSystemException(
"Unable to change path: " + pathName +
": " +
string(exception.what()));
314 auto unixFileName = StringTools::replace(uri,
'\\',
'/');
315 auto lastPathSeparator = StringTools::lastIndexOf(unixFileName,
'/');
316 if (lastPathSeparator == -1)
return ".";
317 return StringTools::substring(unixFileName, 0, lastPathSeparator);
321 auto unixFileName = StringTools::replace(uri,
'\\',
'/');
322 auto lastPathSeparator = StringTools::lastIndexOf(unixFileName,
'/');
323 if (lastPathSeparator == -1)
return uri;
324 return StringTools::substring(unixFileName, lastPathSeparator + 1, unixFileName.length());
328 auto idx = fileName.rfind(
'.');
329 if (idx == string::npos) {
332 return fileName.substr(0, idx);
338 if (std::filesystem::create_directory(std::filesystem::u8path(pathName)) ==
false) {
342 throw FileSystemException(
"Unable to create path: " + pathName +
": " +
string(exception.what()));
348 if (recursive ==
false) {
349 if (std::filesystem::remove(std::filesystem::u8path(pathName)) ==
false) {
353 if (std::filesystem::remove_all(std::filesystem::u8path(pathName)) ==
false) {
358 throw FileSystemException(
"Unable to remove path: " + pathName +
": " +
string(exception.what()));
364 if (std::filesystem::remove(std::filesystem::u8path(
composeURI(pathName, fileName))) ==
false) {
368 throw FileSystemException(
"Unable to remove file: " + pathName +
"/" + fileName +
": " +
string(exception.what()));
374 std::filesystem::rename(std::filesystem::u8path(fileNameFrom), std::filesystem::u8path(fileNameTo));
376 throw FileSystemException(
"Unable to rename file: " + fileNameFrom +
" -> " + fileNameTo +
": " +
string(exception.what()));
382 ifstream ifs(std::filesystem::u8path(
getCanonicalURI(pathName, fileName)), ifstream::binary);
383 if (ifs.is_open() ==
false) {
384 throw FileSystemException(
"Unable to open file for reading(" + to_string(errno) +
"): " + pathName +
"/" + fileName);
388 ifs.seekg( 0, ios::end );
389 size_t size = ifs.tellg();
390 if (size < 12)
return false;
392 array<uint8_t, 12> id;
394 ifs.seekg(size - 12, ios::beg);
395 ifs.read((
char*)
id.data(), 12);
398 if (
id[8] !=
'A' ||
id[9] !=
'T' ||
id[10] !=
'M' ||
id[11] !=
'T') {
402 if (
id[4] !=
'T' ||
id[5] !=
'M' ||
id[6] !=
'B' ||
id[7] !=
'N') {
406 int32_t attachmentSize =
407 ((
static_cast<int32_t
>(
id[0]) & 0xFF) << 24) +
408 ((
static_cast<int32_t
>(
id[1]) & 0xFF) << 16) +
409 ((
static_cast<int32_t
>(
id[2]) & 0xFF) << 8) +
410 ((
static_cast<int32_t
>(
id[3]) & 0xFF) << 0);
413 thumbnailAttachmentContent.resize(attachmentSize);
414 ifs.seekg(size - 12 - attachmentSize, ios::beg);
415 ifs.read((
char*)thumbnailAttachmentContent.data(), attachmentSize);
419 return thumbnailAttachmentContent.empty() ==
false;
423 if (content.size() < 12)
return false;
425 array<uint8_t, 12> id;
428 for (
auto i = 0; i < 12; i++)
id[i] = content[content.size() - 12 + i];
431 if (
id[8] !=
'A' ||
id[9] !=
'T' ||
id[10] !=
'M' ||
id[11] !=
'T') {
435 if (
id[4] !=
'T' ||
id[5] !=
'M' ||
id[6] !=
'B' ||
id[7] !=
'N') {
439 int32_t attachmentSize =
440 ((
static_cast<int32_t
>(
id[0]) & 0xFF) << 24) +
441 ((
static_cast<int32_t
>(
id[1]) & 0xFF) << 16) +
442 ((
static_cast<int32_t
>(
id[2]) & 0xFF) << 8) +
443 ((
static_cast<int32_t
>(
id[3]) & 0xFF) << 0);
446 thumbnailAttachmentContent.resize(attachmentSize);
447 for (
auto i = 0; i < attachmentSize; i++) thumbnailAttachmentContent[i] = content[content.size() - 12 - attachmentSize + i];
450 return thumbnailAttachmentContent.empty() ==
false;
Standard file system implementation.
const string removeFileExtension(const string &fileName)
Remove file extension, e.g.
bool isDrive(const string &uri)
Check if file is a drive (applies to Microsoft Windows only)
void setContentFromString(const string &pathName, const string &fileName, const string &content)
Set content from string.
const string composeURI(const string &pathName, const string &fileName)
Compose URI from path name and file name.
const string getPathName(const string &uri)
Get path name.
const string getCanonicalURI(const string &pathName, const string &fileName)
Get canonical URI from given path name and file name.
~StandardFileSystem()
Public destructor.
void createPath(const string &pathName)
Create path.
bool getThumbnailAttachment(const string &pathName, const string &fileName, vector< uint8_t > &thumbnailAttachmentContent)
Reads a thumbnail attachment from binary file.
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.
void changePath(const string &pathName)
Change path.
void removePath(const string &pathName, bool recursive)
Remove path.
void setExecutable(const string &pathName, const string &fileName) override
Set up file to be an executable file.
void setContent(const string &pathName, const string &fileName, const vector< uint8_t > &content)
Set file content.
void getContent(const string &pathName, const string &fileName, vector< uint8_t > &content)
Get file content.
void setContentFromStringArray(const string &pathName, const string &fileName, const vector< string > &content)
Set file content as string array.
void removeFile(const string &pathName, const string &fileName)
Remove file.
uint64_t getFileSize(const string &pathName, const string &fileName)
Return file size of given file.
void getContentAsStringArray(const string &pathName, const string &fileName, vector< string > &content)
Get file content as string array.
const string getFileName(const string &uri)
Get file name.
bool isPath(const string &uri)
Check if file is a path.
bool exists(const string &uri)
Check if file exists.
const string getCurrentWorkingPathName()
Get current working path name.
bool isExecutable(const string &pathName, const string &fileName) override
Returns if file is a executable file.
const string getContentAsString(const string &pathName, const string &fileName)
Get content as string.
void rename(const string &fileNameFrom, const string &fileNameTo)
Rename file.
const string & nextToken()
void tokenize(const string &str, const string &delimiters, bool emptyTokens=false)
Tokenize.
std::exception Exception
Exception base class.
File system file name filter interface.
virtual bool accept(const string &path, const string &file)=0
Accept a file.