| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #pragma once |
| |
|
| | #include <fstream> |
| | #include <cctype> |
| |
|
| | #if defined(ENV_HAS_STD_FILESYSTEM) |
| | #include <filesystem> |
| | #endif |
| | #if defined(ENV_HAS_POSIX_FILE_STAT) |
| | #include <sys/types.h> |
| | #include <sys/stat.h> |
| | #include <dirent.h> |
| | #include <cstring> |
| | #include "utilities/scalar_guard.hpp" |
| | #endif |
| | #if defined(ENV_HAS_WIN_API) |
| | #include <Windows.h> |
| | #endif |
| |
|
| | #include <string> |
| |
|
| | namespace utilities { |
| | constexpr auto error_size = static_cast<uintmax_t>(-1); |
| |
|
| | enum class file_type { |
| | none, |
| | not_found, |
| | regular, |
| | directory, |
| | symlink, |
| | block, |
| | character, |
| | fifo, |
| | socket, |
| | unknown, |
| | }; |
| |
|
| | inline bool exists(const std::string& path) { |
| | #if defined(ENV_HAS_STD_FILESYSTEM) |
| | return std::filesystem::exists(path); |
| | #elif defined(ENV_HAS_POSIX_FILE_STAT) |
| | struct ::stat path_stat{}; |
| | return 0 == ::stat(path.c_str(), &path_stat); |
| | #else |
| | #error "Unsupported platform, native file system API is required." |
| | #endif |
| | } |
| |
|
| | inline uintmax_t file_size(const std::string& path) { |
| | #if defined(ENV_HAS_STD_FILESYSTEM) |
| | return std::filesystem::file_size(path); |
| | #elif defined(ENV_HAS_POSIX_FILE_STAT) |
| | struct ::stat path_stat{}; |
| | if (0 == ::stat(path.c_str(), &path_stat)) { |
| | return path_stat.st_size; |
| | } |
| | return error_size; |
| | #else |
| | #error "Unsupported platform, native file system API is required." |
| | #endif |
| | } |
| |
|
| | inline file_type status(const std::string& path) { |
| | #if defined(ENV_HAS_STD_FILESYSTEM) |
| | if (!exists(path)) { |
| | return file_type::not_found; |
| | } |
| |
|
| | const auto status = std::filesystem::status(path); |
| | if (std::filesystem::is_regular_file(status)) { |
| | return file_type::regular; |
| | } |
| | if (std::filesystem::is_directory(status)) { |
| | return file_type::directory; |
| | } |
| | if (std::filesystem::is_symlink(status)) { |
| | return file_type::symlink; |
| | } |
| | if (std::filesystem::is_block_file(status)) { |
| | return file_type::block; |
| | } |
| | if (std::filesystem::is_character_file(status)) { |
| | return file_type::character; |
| | } |
| | if (std::filesystem::is_fifo(status)) { |
| | return file_type::fifo; |
| | } |
| | if (std::filesystem::is_socket(status)) { |
| | return file_type::socket; |
| | } |
| | return file_type::unknown; |
| | #elif defined(ENV_HAS_POSIX_FILE_STAT) |
| | struct ::stat path_stat{}; |
| | if (0 != ::stat(path.c_str(), &path_stat)) { |
| | return file_type::not_found; |
| | } |
| |
|
| | if (S_ISREG(path_stat.st_mode)) { |
| | return file_type::regular; |
| | } |
| | if (S_ISDIR(path_stat.st_mode)) { |
| | return file_type::directory; |
| | } |
| | if (S_ISLNK(path_stat.st_mode)) { |
| | return file_type::symlink; |
| | } |
| | if (S_ISBLK(path_stat.st_mode)) { |
| | return file_type::block; |
| | } |
| | if (S_ISCHR(path_stat.st_mode)) { |
| | return file_type::character; |
| | } |
| | if (S_ISFIFO(path_stat.st_mode)) { |
| | return file_type::fifo; |
| | } |
| | if (S_ISSOCK(path_stat.st_mode)) { |
| | return file_type::socket; |
| | } |
| | return file_type::unknown; |
| | #else |
| | #error "Unsupported platform, native file system API is required." |
| | #endif |
| | } |
| |
|
| | inline bool is_regular_file(const std::string& path) { |
| | #if defined(ENV_HAS_STD_FILESYSTEM) |
| | return std::filesystem::is_regular_file(path); |
| | #elif defined(ENV_HAS_POSIX_FILE_STAT) |
| | struct ::stat path_stat{}; |
| | return 0 == ::stat(path.c_str(), &path_stat) && S_ISREG(path_stat.st_mode); |
| | #else |
| | #error "Unsupported platform, native file system API is required." |
| | #endif |
| | } |
| |
|
| | inline bool is_directory(const std::string& path) { |
| | #if defined(ENV_HAS_STD_FILESYSTEM) |
| | return std::filesystem::is_directory(path); |
| | #elif defined(ENV_HAS_POSIX_FILE_STAT) |
| | struct ::stat path_stat{}; |
| | return 0 == ::stat(path.c_str(), &path_stat) && S_ISDIR(path_stat.st_mode); |
| | #else |
| | #error "Unsupported platform, native file system API is required." |
| | #endif |
| | } |
| |
|
| | inline bool is_empty(const std::string& path) { |
| | #if defined(ENV_HAS_STD_FILESYSTEM) |
| | return std::filesystem::is_empty(path); |
| | #elif defined(ENV_HAS_POSIX_FILE_STAT) |
| | if (!exists(path)) |
| | return false; |
| |
|
| | if (is_regular_file(path)) |
| | return 0 == file_size(path); |
| | if (is_directory(path)) { |
| | auto dir = scalar_guard<DIR*>(::opendir(path.c_str()), ::closedir); |
| | if (nullptr == dir.get()) { |
| | return false; |
| | } |
| |
|
| | struct ::dirent* entry; |
| | while ((entry = ::readdir(dir.get())) != nullptr) { |
| | if (0 != ::strcmp(entry->d_name, ".") && 0 != ::strcmp(entry->d_name, "..")) { |
| | return false; |
| | } |
| | } |
| | return true; |
| | } |
| | return false; |
| | #else |
| | #error "Unsupported platform, native file system API is required." |
| | #endif |
| | } |
| |
|
| | inline bool read(const std::string& file, void* data, const uintmax_t& size) { |
| | std::ifstream stream; |
| | stream.open(file, std::ios_base::binary | std::ios_base::in); |
| | if (stream.is_open()) { |
| | stream.read(static_cast<char*>(data), static_cast<std::streamsize>(size)); |
| | stream.close(); |
| | return true; |
| | } |
| | return false; |
| | } |
| |
|
| | inline bool write(const std::string& file, const void* data, const uintmax_t& size) { |
| | std::ofstream stream; |
| | stream.open(file, std::ios_base::binary | std::ios_base::out); |
| | if (stream.is_open()) { |
| | stream.write(static_cast<const char*>(data), static_cast<std::streamsize>(size)); |
| | stream.close(); |
| | return true; |
| | } |
| | return false; |
| | } |
| |
|
| | inline bool create_directory(const std::string& path) { |
| | #if defined(ENV_HAS_STD_FILESYSTEM) |
| | return std::filesystem::create_directories(path); |
| | #elif defined(ENV_HAS_POSIX_FILE_STAT) |
| | return 0 == ::mkdir(path.c_str(), 0755); |
| | #else |
| | #error "Unsupported platform, native file system API is required." |
| | #endif |
| | } |
| |
|
| | inline std::string get_file_name(const std::string& file) { |
| | #if defined(ENV_HAS_STD_FILESYSTEM) |
| | return std::filesystem::path(file).filename().string(); |
| | #else |
| | if (const auto pos = file.find_last_of("/\\"); std::string::npos != pos) { |
| | return file.substr(pos + 1); |
| | } |
| | return file; |
| | #endif |
| | } |
| |
|
| | inline std::string get_file_extension(const std::string& file) { |
| | #if defined(ENV_HAS_STD_FILESYSTEM) |
| | return std::filesystem::path(file).extension().string(); |
| | #else |
| | if (const auto pos = file.find_last_of('.'); std::string::npos != pos) { |
| | return file.substr(pos + 1); |
| | } |
| | return ""; |
| | #endif |
| | } |
| |
|
| | inline std::string get_legal_name(const std::string& name) { |
| | std::string temp = name; |
| |
|
| | size_t pos = temp.find_last_of("/\\"); |
| | if (pos != std::string::npos) pos = 0; |
| |
|
| | for (size_t i = pos; i < temp.size(); ++i) |
| | if (!(::isalnum(temp[i]) || '-' == temp[i] || '_' == temp[i])) temp[i] = '_'; |
| | return temp; |
| | } |
| |
|
| | } |
| |
|