intial commit

This commit is contained in:
2023-05-29 14:51:44 +02:00
commit da781b87f2
38 changed files with 4842 additions and 0 deletions

View File

@@ -0,0 +1,128 @@
#include "./filesystem.hpp"
namespace mijin
{
//
// internal defines
//
//
// internal constants
//
//
// internal types
//
//
// internal variables
//
//
// internal functions
//
//
// public functions
//
std::vector<fs::path> OSFileSystemAdapter::getRoots()
{
return {
"/" // TODO: other OSs
};
}
fs::path OSFileSystemAdapter::getHomeFolder()
{
return "/home/mewin"; // very TODO
}
std::vector<FileInfo> OSFileSystemAdapter::listFiles(const fs::path& folder)
{
std::vector<FileInfo> entries;
std::error_code err;
fs::directory_iterator iterator(folder, fs::directory_options::skip_permission_denied, err);
if (err) {
return {}; // TODO: propagate?
}
for (const fs::directory_entry& entry : iterator)
{
FileInfo& info = entries.emplace_back();
info.path = entry.path();
info.exists = true;
info.isFolder = entry.is_directory(err);
info.isSymlink = entry.is_symlink(err);
info.isSpecial = !info.isFolder && !entry.is_regular_file(err);
info.isHidden = info.path.filename().string().starts_with('.'); // at least for Linux
if (info.isFolder) {
try {
info.size = std::distance(fs::directory_iterator(info.path), fs::directory_iterator());
}
catch(std::runtime_error&) {
info.size = 0;
}
}
else if (!info.isSpecial)
{
info.size = entry.file_size(err);
if (err) {
info.size = 0;
}
}
}
return entries;
}
FileInfo OSFileSystemAdapter::getFileInfo(const fs::path& file)
{
FileInfo info = {};
std::error_code err;
info.path = file;
info.exists = fs::exists(file, err);
if (info.exists)
{
info.isFolder = fs::is_directory(file, err);
info.isSymlink = fs::is_symlink(file, err);
info.isSpecial = !info.isFolder && !fs::is_regular_file(file, err);
info.isHidden = info.path.filename().string().starts_with('.'); // at least for Linux
if (info.isFolder) {
try {
info.size = std::distance(fs::directory_iterator(info.path), fs::directory_iterator());
}
catch(std::runtime_error&) {
info.size = 0;
}
}
else if (!info.isSpecial)
{
info.size = fs::file_size(file, err);
if (err) {
info.size = 0;
}
}
}
return info;
}
StreamError OSFileSystemAdapter::open(const fs::path& path, FileOpenMode mode, std::unique_ptr<Stream>& outStream)
{
const std::string pathStr = path.string();
auto stream = std::make_unique<FileStream>();
const StreamError error = stream->open(pathStr.c_str(), mode);
if (error != StreamError::SUCCESS) {
return error;
}
outStream = std::move(stream);
return StreamError::SUCCESS;
}
OSFileSystemAdapter& OSFileSystemAdapter::getInstance() // static
{
static OSFileSystemAdapter instance;
return instance;
}
} // namespace mijin

View File

@@ -0,0 +1,105 @@
#pragma once
#if !defined(MIJIN_VIRTUAL_FILESYSTEM_FILESYSTEM_HPP_INCLUDED)
#define MIJIN_VIRTUAL_FILESYSTEM_FILESYSTEM_HPP_INCLUDED 1
#include <array>
#include <cmath>
#include <filesystem>
#include <sstream>
#include <string>
#include <vector>
#include "../io/stream.hpp"
namespace fs = std::filesystem;
namespace mijin
{
//
// public defines
//
//
// public constants
//
//
// public types
//
struct FileInfo
{
fs::path path;
std::size_t size = 0;
bool exists : 1 = false;
bool isFolder : 1 = false;
bool isSymlink : 1 = false;
bool isSpecial : 1 = false;
bool isHidden : 1 = false;
};
class FileSystemAdapter
{
public:
virtual ~FileSystemAdapter() = default;
[[nodiscard]] virtual std::vector<fs::path> getRoots() = 0;
[[nodiscard]] virtual fs::path getHomeFolder() = 0;
[[nodiscard]] virtual std::vector<FileInfo> listFiles(const fs::path& folder) = 0;
[[nodiscard]] virtual FileInfo getFileInfo(const fs::path& file) = 0;
[[nodiscard]] virtual StreamError open(const fs::path& path, FileOpenMode mode, std::unique_ptr<Stream>& outStream) = 0;
};
class OSFileSystemAdapter : public FileSystemAdapter
{
public:
std::vector<fs::path> getRoots() override;
fs::path getHomeFolder() override;
std::vector<FileInfo> listFiles(const fs::path& folder) override;
FileInfo getFileInfo(const fs::path& file) override;
StreamError open(const fs::path& path, FileOpenMode mode, std::unique_ptr<Stream>& outStream) override;
static OSFileSystemAdapter& getInstance();
};
//
// public functions
//
inline std::string formatFileType(const FileInfo& info)
{
if (info.isFolder) {
return "Folder";
}
if (info.isSpecial) {
return "Special";
}
return "File";
}
inline std::string formatFileSize(std::size_t sizeInBytes)
{
static constexpr std::array suffixes = {"bytes", "KiB", "MiB", "GiB", "TiB"}; // enough?
if (sizeInBytes == 0) {
return "0 bytes";
}
const std::size_t pos = std::min(static_cast<std::size_t>(std::ceil(std::log2(sizeInBytes))) / 10, suffixes.size() - 1);
std::stringstream oss;
oss << std::setprecision(2) << std::fixed;
if (pos == 0) {
oss << sizeInBytes << " bytes";
}
else
{
const float converted = static_cast<float>(sizeInBytes) / std::pow(2.f, 10.f * static_cast<float>(pos));
oss << converted << " " << suffixes[pos];
}
return oss.str();
}
} // namespace mijin
#endif // !defined(MIJIN_VIRTUAL_FILESYSTEM_FILESYSTEM_HPP_INCLUDED)

View File

@@ -0,0 +1,87 @@
#pragma once
#if !defined(MIJIN_VIRTUAL_FILESYSTEM_RELATIVE_HPP_INCLUDED)
#define MIJIN_VIRTUAL_FILESYSTEM_RELATIVE_HPP_INCLUDED 1
#include "./filesystem.hpp"
namespace mijin
{
//
// public defines
//
//
// public constants
//
//
// public types
//
template<typename TWrapped>
class RelativeFileSystemAdapter : public FileSystemAdapter
{
private:
TWrapped wrapped_;
fs::path root_;
public:
template<typename... TArgs>
explicit RelativeFileSystemAdapter(fs::path root, TArgs&&... args)
: wrapped_(std::forward<TArgs>(args)...), root_(std::move(root)) {}
RelativeFileSystemAdapter(const RelativeFileSystemAdapter&) = default;
RelativeFileSystemAdapter(RelativeFileSystemAdapter&&) noexcept = default;
RelativeFileSystemAdapter& operator=(const RelativeFileSystemAdapter&) = default;
RelativeFileSystemAdapter& operator=(RelativeFileSystemAdapter&&) noexcept = default;
std::vector<fs::path> getRoots() override;
fs::path getHomeFolder() override;
std::vector<FileInfo> listFiles(const fs::path& folder) override;
FileInfo getFileInfo(const fs::path& file) override;
StreamError open(const fs::path& path, FileOpenMode mode, std::unique_ptr<Stream>& outStream) override;
};
//
// public functions
//
template<typename TWrapped>
std::vector<fs::path> RelativeFileSystemAdapter<TWrapped>::getRoots()
{
return { root_ };
}
template<typename TWrapped>
fs::path RelativeFileSystemAdapter<TWrapped>::getHomeFolder()
{
return root_;
}
template<typename TWrapped>
std::vector<FileInfo> RelativeFileSystemAdapter<TWrapped>::listFiles(const fs::path& folder)
{
std::vector<FileInfo> result = wrapped_.listFiles(root_ / folder);
for (FileInfo& fileInfo : result) {
fileInfo.path = "/" / fileInfo.path.lexically_relative(root_);
}
return result;
}
template<typename TWrapped>
FileInfo RelativeFileSystemAdapter<TWrapped>::getFileInfo(const fs::path& file)
{
return wrapped_.getFileInfo(root_ / file);
}
template<typename TWrapped>
StreamError RelativeFileSystemAdapter<TWrapped>::open(const fs::path& path, FileOpenMode mode, std::unique_ptr<Stream>& outStream)
{
return wrapped_.open(root_ / path, mode, outStream);
}
} // namespace mijin
#endif // !defined(MIJIN_VIRTUAL_FILESYSTEM_RELATIVE_HPP_INCLUDED)

View File

@@ -0,0 +1,105 @@
#include "./stacked.hpp"
#include <algorithm>
namespace mijin
{
//
// internal defines
//
//
// internal constants
//
//
// internal types
//
//
// internal variables
//
//
// internal functions
//
//
// public functions
//
std::vector<fs::path> StackedFileSystemAdapter::getRoots()
{
std::vector<fs::path> roots;
for (auto& adapter : adapters_)
{
for (const fs::path& root : adapter->getRoots())
{
auto it = std::find(roots.begin(), roots.end(), root);
if (it == roots.end()) {
roots.push_back(root);
}
}
}
return roots;
}
fs::path StackedFileSystemAdapter::getHomeFolder()
{
if (adapters_.empty()) {
return fs::path();
}
return adapters_.front()->getHomeFolder();
}
std::vector<FileInfo> StackedFileSystemAdapter::listFiles(const fs::path& folder)
{
std::vector<FileInfo> files;
for (auto& adapter : adapters_)
{
for (const FileInfo& file : adapter->listFiles(folder))
{
auto it = std::find_if(files.begin(), files.end(), [&](const FileInfo& existing)
{
return existing.path == file.path;
});
if (it != files.end()) {
files.push_back(file);
}
}
}
return files;
}
FileInfo StackedFileSystemAdapter::getFileInfo(const fs::path& file)
{
for (auto& adapter : adapters_)
{
FileInfo fileInfo = adapter->getFileInfo(file);
if (fileInfo.exists) {
return fileInfo;
}
}
return {};
}
StreamError StackedFileSystemAdapter::open(const fs::path& path, FileOpenMode mode, std::unique_ptr<Stream>& outStream)
{
for (auto& adapter : adapters_)
{
FileInfo fileInfo = adapter->getFileInfo(path);
if (fileInfo.exists) {
return adapter->open(path, mode, outStream);
}
}
return StreamError::IO_ERROR;
}
} // namespace mijin

View File

@@ -0,0 +1,52 @@
#pragma once
#if !defined(MIJIN_VIRTUAL_FILESYSTEM_STACKED_HPP_INCLUDED)
#define MIJIN_VIRTUAL_FILESYSTEM_STACKED_HPP_INCLUDED 1
#include <memory>
#include <vector>
#include "./filesystem.hpp"
namespace mijin
{
//
// public defines
//
//
// public constants
//
//
// public types
//
class StackedFileSystemAdapter : public FileSystemAdapter
{
private:
std::vector<std::unique_ptr<FileSystemAdapter>> adapters_;
public:
std::vector<fs::path> getRoots() override;
fs::path getHomeFolder() override;
std::vector<FileInfo> listFiles(const fs::path& folder) override;
FileInfo getFileInfo(const fs::path& file) override;
StreamError open(const fs::path& path, FileOpenMode mode, std::unique_ptr<Stream>& outStream) override;
inline void addAdapter(std::unique_ptr<FileSystemAdapter>&& adapter) {
adapters_.push_back(std::move(adapter));
}
template<typename TAdapter, typename... TArgs>
inline void emplaceAdapter(TArgs&&... args) {
addAdapter(std::make_unique<TAdapter>(std::forward<TArgs>(args)...));
}
};
//
// public functions
//
} // namespace mijin
#endif // !defined(MIJIN_VIRTUAL_FILESYSTEM_STACKED_HPP_INCLUDED)