123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- #pragma once
- #include <nall/file.hpp>
- #include <nall/function.hpp>
- #include <nall/inode.hpp>
- #include <nall/intrinsics.hpp>
- #include <nall/merge-sort.hpp>
- #include <nall/string.hpp>
- #include <nall/vector.hpp>
- #if defined(PLATFORM_WINDOWS)
- #include <nall/windows/utf8.hpp>
- #else
- #include <dirent.h>
- #include <stdio.h>
- #include <sys/types.h>
- #endif
- namespace nall {
- struct directory : inode {
- directory() = delete;
- static auto copy(const string& source, const string& target) -> bool; //recursive
- static auto create(const string& pathname, uint permissions = 0755) -> bool; //recursive
- static auto remove(const string& pathname) -> bool; //recursive
- static auto exists(const string& pathname) -> bool;
- static auto folders(const string& pathname, const string& pattern = "*") -> vector<string> {
- auto folders = directory::ufolders(pathname, pattern);
- folders.sort();
- for(auto& folder : folders) folder.append("/"); //must append after sorting
- return folders;
- }
- static auto files(const string& pathname, const string& pattern = "*") -> vector<string> {
- auto files = directory::ufiles(pathname, pattern);
- files.sort();
- return files;
- }
- static auto contents(const string& pathname, const string& pattern = "*") -> vector<string> {
- auto folders = directory::ufolders(pathname); //pattern search of contents should only filter files
- folders.sort();
- for(auto& folder : folders) folder.append("/"); //must append after sorting
- auto files = directory::ufiles(pathname, pattern);
- files.sort();
- for(auto& file : files) folders.append(file);
- return folders;
- }
- static auto ifolders(const string& pathname, const string& pattern = "*") -> vector<string> {
- auto folders = ufolders(pathname, pattern);
- folders.isort();
- for(auto& folder : folders) folder.append("/"); //must append after sorting
- return folders;
- }
- static auto ifiles(const string& pathname, const string& pattern = "*") -> vector<string> {
- auto files = ufiles(pathname, pattern);
- files.isort();
- return files;
- }
- static auto icontents(const string& pathname, const string& pattern = "*") -> vector<string> {
- auto folders = directory::ufolders(pathname); //pattern search of contents should only filter files
- folders.isort();
- for(auto& folder : folders) folder.append("/"); //must append after sorting
- auto files = directory::ufiles(pathname, pattern);
- files.isort();
- for(auto& file : files) folders.append(file);
- return folders;
- }
- static auto rcontents(const string& pathname, const string& pattern = "*") -> vector<string> {
- vector<string> contents;
- function<void (const string&, const string&, const string&)>
- recurse = [&](const string& basename, const string& pathname, const string& pattern) {
- for(auto& folder : directory::ufolders(pathname)) {
- contents.append(string{pathname, folder, "/"}.trimLeft(basename, 1L));
- recurse(basename, {pathname, folder, "/"}, pattern);
- }
- for(auto& file : directory::ufiles(pathname, pattern)) {
- contents.append(string{pathname, file}.trimLeft(basename, 1L));
- }
- };
- for(auto& folder : directory::ufolders(pathname)) {
- contents.append({folder, "/"});
- recurse(pathname, {pathname, folder, "/"}, pattern);
- }
- for(auto& file : directory::ufiles(pathname, pattern)) {
- contents.append(file);
- }
- contents.sort();
- return contents;
- }
- static auto ircontents(const string& pathname, const string& pattern = "*") -> vector<string> {
- vector<string> contents;
- function<void (const string&, const string&, const string&)>
- recurse = [&](const string& basename, const string& pathname, const string& pattern) {
- for(auto& folder : directory::ufolders(pathname)) {
- contents.append(string{pathname, folder, "/"}.trimLeft(basename, 1L));
- recurse(basename, {pathname, folder, "/"}, pattern);
- }
- for(auto& file : directory::ufiles(pathname, pattern)) {
- contents.append(string{pathname, file}.trimLeft(basename, 1L));
- }
- };
- for(auto& folder : directory::ufolders(pathname)) {
- contents.append({folder, "/"});
- recurse(pathname, {pathname, folder, "/"}, pattern);
- }
- for(auto& file : directory::ufiles(pathname, pattern)) {
- contents.append(file);
- }
- contents.isort();
- return contents;
- }
- static auto rfolders(const string& pathname, const string& pattern = "*") -> vector<string> {
- vector<string> folders;
- for(auto& folder : rcontents(pathname, pattern)) {
- if(directory::exists({pathname, folder})) folders.append(folder);
- }
- return folders;
- }
- static auto irfolders(const string& pathname, const string& pattern = "*") -> vector<string> {
- vector<string> folders;
- for(auto& folder : ircontents(pathname, pattern)) {
- if(directory::exists({pathname, folder})) folders.append(folder);
- }
- return folders;
- }
- static auto rfiles(const string& pathname, const string& pattern = "*") -> vector<string> {
- vector<string> files;
- for(auto& file : rcontents(pathname, pattern)) {
- if(file::exists({pathname, file})) files.append(file);
- }
- return files;
- }
- static auto irfiles(const string& pathname, const string& pattern = "*") -> vector<string> {
- vector<string> files;
- for(auto& file : ircontents(pathname, pattern)) {
- if(file::exists({pathname, file})) files.append(file);
- }
- return files;
- }
- private:
- //internal functions; these return unsorted lists
- static auto ufolders(const string& pathname, const string& pattern = "*") -> vector<string>;
- static auto ufiles(const string& pathname, const string& pattern = "*") -> vector<string>;
- };
- inline auto directory::copy(const string& source, const string& target) -> bool {
- bool result = true;
- if(!directory::create(target)) return result = false;
- for(auto& name : directory::folders(source)) {
- if(!directory::copy({source, name}, {target, name})) result = false;
- }
- for(auto& name : directory::files(source)) {
- if(!file::copy({source, name}, {target, name})) result = false;
- }
- return result;
- }
- #if defined(PLATFORM_WINDOWS)
- inline auto directory::create(const string& pathname, uint permissions) -> bool {
- string path;
- auto list = string{pathname}.transform("\\", "/").trimRight("/").split("/");
- bool result = true;
- for(auto& part : list) {
- path.append(part, "/");
- if(directory::exists(path)) continue;
- result &= (_wmkdir(utf16_t(path)) == 0);
- }
- return result;
- }
- inline auto directory::remove(const string& pathname) -> bool {
- auto list = directory::contents(pathname);
- for(auto& name : list) {
- if(name.endsWith("/")) directory::remove({pathname, name});
- else file::remove({pathname, name});
- }
- return _wrmdir(utf16_t(pathname)) == 0;
- }
- inline auto directory::exists(const string& pathname) -> bool {
- string name = pathname;
- name.trim("\"", "\"");
- DWORD result = GetFileAttributes(utf16_t(name));
- if(result == INVALID_FILE_ATTRIBUTES) return false;
- return (result & FILE_ATTRIBUTE_DIRECTORY);
- }
- inline auto directory::ufolders(const string& pathname, const string& pattern) -> vector<string> {
- if(!pathname) {
- //special root pseudo-folder (return list of drives)
- wchar_t drives[PATH_MAX] = {0};
- GetLogicalDriveStrings(PATH_MAX, drives);
- wchar_t* p = drives;
- while(*p || *(p + 1)) {
- if(!*p) *p = ';';
- *p++;
- }
- return string{(const char*)utf8_t(drives)}.replace("\\", "/").split(";");
- }
- vector<string> list;
- string path = pathname;
- path.transform("/", "\\");
- if(!path.endsWith("\\")) path.append("\\");
- path.append("*");
- HANDLE handle;
- WIN32_FIND_DATA data;
- handle = FindFirstFile(utf16_t(path), &data);
- if(handle != INVALID_HANDLE_VALUE) {
- if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
- if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- string name = (const char*)utf8_t(data.cFileName);
- if(name.match(pattern)) list.append(name);
- }
- }
- while(FindNextFile(handle, &data) != false) {
- if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
- if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- string name = (const char*)utf8_t(data.cFileName);
- if(name.match(pattern)) list.append(name);
- }
- }
- }
- FindClose(handle);
- }
- return list;
- }
- inline auto directory::ufiles(const string& pathname, const string& pattern) -> vector<string> {
- if(!pathname) return {};
- vector<string> list;
- string path = pathname;
- path.transform("/", "\\");
- if(!path.endsWith("\\")) path.append("\\");
- path.append("*");
- HANDLE handle;
- WIN32_FIND_DATA data;
- handle = FindFirstFile(utf16_t(path), &data);
- if(handle != INVALID_HANDLE_VALUE) {
- if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
- string name = (const char*)utf8_t(data.cFileName);
- if(name.match(pattern)) list.append(name);
- }
- while(FindNextFile(handle, &data) != false) {
- if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
- string name = (const char*)utf8_t(data.cFileName);
- if(name.match(pattern)) list.append(name);
- }
- }
- FindClose(handle);
- }
- return list;
- }
- #else
- inline auto directoryIsFolder(DIR* dp, struct dirent* ep) -> bool {
- if(ep->d_type == DT_DIR) return true;
- if(ep->d_type == DT_LNK || ep->d_type == DT_UNKNOWN) {
- //symbolic links must be resolved to determine type
- struct stat sp = {0};
- fstatat(dirfd(dp), ep->d_name, &sp, 0);
- return S_ISDIR(sp.st_mode);
- }
- return false;
- }
- inline auto directory::create(const string& pathname, uint permissions) -> bool {
- string path;
- auto list = string{pathname}.trimRight("/").split("/");
- bool result = true;
- for(auto& part : list) {
- path.append(part, "/");
- if(directory::exists(path)) continue;
- result &= (mkdir(path, permissions) == 0);
- }
- return result;
- }
- inline auto directory::remove(const string& pathname) -> bool {
- auto list = directory::contents(pathname);
- for(auto& name : list) {
- if(name.endsWith("/")) directory::remove({pathname, name});
- else file::remove({pathname, name});
- }
- return rmdir(pathname) == 0;
- }
- inline auto directory::exists(const string& pathname) -> bool {
- struct stat data;
- if(stat(pathname, &data) != 0) return false;
- return S_ISDIR(data.st_mode);
- }
- inline auto directory::ufolders(const string& pathname, const string& pattern) -> vector<string> {
- if(!pathname) return vector<string>{"/"};
- vector<string> list;
- DIR* dp;
- struct dirent* ep;
- dp = opendir(pathname);
- if(dp) {
- while(ep = readdir(dp)) {
- if(!strcmp(ep->d_name, ".")) continue;
- if(!strcmp(ep->d_name, "..")) continue;
- if(!directoryIsFolder(dp, ep)) continue;
- string name{ep->d_name};
- if(name.match(pattern)) list.append(std::move(name));
- }
- closedir(dp);
- }
- return list;
- }
- inline auto directory::ufiles(const string& pathname, const string& pattern) -> vector<string> {
- if(!pathname) return {};
- vector<string> list;
- DIR* dp;
- struct dirent* ep;
- dp = opendir(pathname);
- if(dp) {
- while(ep = readdir(dp)) {
- if(!strcmp(ep->d_name, ".")) continue;
- if(!strcmp(ep->d_name, "..")) continue;
- if(directoryIsFolder(dp, ep)) continue;
- string name{ep->d_name};
- if(name.match(pattern)) list.append(std::move(name));
- }
- closedir(dp);
- }
- return list;
- }
- #endif
- }
|