148 lines
3.9 KiB
C++
148 lines
3.9 KiB
C++
|
|
#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"
|
|
#include "../util/hash.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;
|
|
};
|
|
|
|
// basically just a thin wrapper around adapter + path, for utility
|
|
class PathReference
|
|
{
|
|
private:
|
|
class FileSystemAdapter* adapter_;
|
|
fs::path path_;
|
|
public:
|
|
PathReference(class FileSystemAdapter* adapter, fs::path path) noexcept : adapter_(adapter), path_(std::move(path)) {}
|
|
|
|
auto operator<=>(const PathReference& other) const noexcept = default;
|
|
|
|
[[nodiscard]] class FileSystemAdapter* getAdapter() const noexcept { return adapter_; }
|
|
[[nodiscard]] const fs::path& getPath() const noexcept { return path_; }
|
|
[[nodiscard]] inline FileInfo getInfo() const;
|
|
[[nodiscard]] inline StreamError open(FileOpenMode mode, std::unique_ptr<Stream>& outStream) const;
|
|
};
|
|
|
|
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;
|
|
|
|
[[nodiscard]] PathReference getPath(fs::path path) noexcept { return PathReference(this, std::move(path)); }
|
|
};
|
|
|
|
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 FileInfo PathReference::getInfo() const
|
|
{
|
|
return adapter_->getFileInfo(path_);
|
|
}
|
|
|
|
inline StreamError PathReference::open(FileOpenMode mode, std::unique_ptr<Stream>& outStream) const
|
|
{
|
|
return adapter_->open(path_, mode, outStream);
|
|
}
|
|
|
|
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
|
|
|
|
template<>
|
|
struct std::hash<mijin::PathReference>
|
|
{
|
|
std::size_t operator()(const mijin::PathReference& pathRef) const noexcept
|
|
{
|
|
std::size_t hash = 0;
|
|
mijin::hashCombine(hash, pathRef.getAdapter());
|
|
mijin::hashCombine(hash, pathRef.getPath());
|
|
return hash;
|
|
}
|
|
};
|
|
|
|
#endif // !defined(MIJIN_VIRTUAL_FILESYSTEM_FILESYSTEM_HPP_INCLUDED)
|