176 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			176 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
 | 
						|
#pragma once
 | 
						|
 | 
						|
#if !defined(MIJIN_VIRTUAL_FILESYSTEM_MAPPING_HPP_INCLUDED)
 | 
						|
#define MIJIN_VIRTUAL_FILESYSTEM_MAPPING_HPP_INCLUDED 1
 | 
						|
 | 
						|
#include <algorithm>
 | 
						|
#include "./filesystem.hpp"
 | 
						|
#include "../internal/common.hpp"
 | 
						|
 | 
						|
namespace mijin
 | 
						|
{
 | 
						|
 | 
						|
//
 | 
						|
// public defines
 | 
						|
//
 | 
						|
 | 
						|
//
 | 
						|
// public constants
 | 
						|
//
 | 
						|
 | 
						|
//
 | 
						|
// public types
 | 
						|
//
 | 
						|
 | 
						|
template<typename TWrapped>
 | 
						|
class MappingFileSystemAdapter : public FileSystemAdapter
 | 
						|
{
 | 
						|
private:
 | 
						|
    TWrapped wrapped_;
 | 
						|
    fs::path root_;
 | 
						|
public:
 | 
						|
    template<typename... TArgs>
 | 
						|
    explicit MappingFileSystemAdapter(fs::path root, TArgs&&... args)
 | 
						|
            : wrapped_(std::forward<TArgs>(args)...), root_(std::move(root)) {}
 | 
						|
    MappingFileSystemAdapter(const MappingFileSystemAdapter&) = default;
 | 
						|
    MappingFileSystemAdapter(MappingFileSystemAdapter&&) MIJIN_NOEXCEPT = default;
 | 
						|
 | 
						|
    MappingFileSystemAdapter& operator=(const MappingFileSystemAdapter&) = default;
 | 
						|
    MappingFileSystemAdapter& operator=(MappingFileSystemAdapter&&) MIJIN_NOEXCEPT = default;
 | 
						|
 | 
						|
    fs::path getHomeFolder() override;
 | 
						|
    std::vector<FileInfo> listFiles(const fs::path& folder) override;
 | 
						|
    FileInfo getFileInfo(const fs::path& file) override;
 | 
						|
    Optional<fs::path> getNativePath(const fs::path& file) override;
 | 
						|
    StreamError open(const fs::path& path, FileOpenMode mode, std::unique_ptr<Stream>& outStream) override;
 | 
						|
private:
 | 
						|
    bool adjustPath(fs::path& path) const MIJIN_NOEXCEPT;
 | 
						|
};
 | 
						|
 | 
						|
//
 | 
						|
// public functions
 | 
						|
//
 | 
						|
 | 
						|
template<typename TWrapped>
 | 
						|
fs::path MappingFileSystemAdapter<TWrapped>::getHomeFolder()
 | 
						|
{
 | 
						|
    return "/";
 | 
						|
}
 | 
						|
 | 
						|
template<typename TWrapped>
 | 
						|
std::vector<FileInfo> MappingFileSystemAdapter<TWrapped>::listFiles(const fs::path& folder)
 | 
						|
{
 | 
						|
    fs::path adjusted = folder;
 | 
						|
    if (!adjustPath(adjusted))
 | 
						|
    {
 | 
						|
        return {};
 | 
						|
    }
 | 
						|
 | 
						|
    std::vector<FileInfo> result;
 | 
						|
    result = wrapped_.listFiles(adjusted);
 | 
						|
    for (FileInfo& fileInfo : result)
 | 
						|
    {
 | 
						|
        fileInfo.path = root_ / fileInfo.path;
 | 
						|
    }
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
template<typename TWrapped>
 | 
						|
FileInfo MappingFileSystemAdapter<TWrapped>::getFileInfo(const fs::path& file)
 | 
						|
{
 | 
						|
    fs::path adjusted = file;
 | 
						|
    if (!adjustPath(adjusted))
 | 
						|
    {
 | 
						|
        return {};
 | 
						|
    }
 | 
						|
 | 
						|
    return wrapped_.getFileInfo(adjusted);
 | 
						|
}
 | 
						|
 | 
						|
template<typename TWrapped>
 | 
						|
Optional<fs::path> MappingFileSystemAdapter<TWrapped>::getNativePath(const fs::path& file)
 | 
						|
{
 | 
						|
    fs::path adjusted = file;
 | 
						|
    if (!adjustPath(adjusted))
 | 
						|
    {
 | 
						|
        return {};
 | 
						|
    }
 | 
						|
 | 
						|
    return wrapped_.getNativePath(adjusted);
 | 
						|
}
 | 
						|
 | 
						|
template<typename TWrapped>
 | 
						|
StreamError MappingFileSystemAdapter<TWrapped>::open(const fs::path& path, FileOpenMode mode, std::unique_ptr<Stream>& outStream)
 | 
						|
{
 | 
						|
    fs::path adjusted = path;
 | 
						|
    if (!adjustPath(adjusted))
 | 
						|
    {
 | 
						|
        return {};
 | 
						|
    }
 | 
						|
 | 
						|
    return wrapped_.open(adjusted, mode, outStream);
 | 
						|
}
 | 
						|
 | 
						|
template<typename TWrapped>
 | 
						|
bool MappingFileSystemAdapter<TWrapped>::adjustPath(fs::path& path) const MIJIN_NOEXCEPT
 | 
						|
{
 | 
						|
    if (!path.is_absolute())
 | 
						|
    {
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    // checks whether path starts with root
 | 
						|
    auto [itRoot, itPath] = std::mismatch(root_.begin(), root_.end(), path.begin(), path.end());
 | 
						|
    if (itRoot != root_.end())
 | 
						|
    {
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    std::error_code error;
 | 
						|
    fs::path wrapped = fs::relative(path, root_, error);
 | 
						|
 | 
						|
    if (wrapped.empty() || error)
 | 
						|
    {
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
    path = std::move(wrapped);
 | 
						|
    return true;
 | 
						|
}
 | 
						|
 | 
						|
namespace vfs_pipe
 | 
						|
{
 | 
						|
template<typename TBase>
 | 
						|
struct MappingBuilder : Builder<MappingBuilder<TBase>, MappingFileSystemAdapter<typename TBase::adapter_t>>
 | 
						|
{
 | 
						|
    fs::path root;
 | 
						|
    TBase base;
 | 
						|
 | 
						|
    std::unique_ptr<MappingFileSystemAdapter<typename TBase::adapter_t>> build()
 | 
						|
    {
 | 
						|
        return std::make_unique<MappingFileSystemAdapter<typename TBase::adapter_t>>(root, std::move(*base.build()));
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
struct MappingOptions
 | 
						|
{
 | 
						|
    fs::path root;
 | 
						|
};
 | 
						|
 | 
						|
[[nodiscard]]
 | 
						|
inline MappingOptions map_to(fs::path root) noexcept
 | 
						|
{
 | 
						|
    return {.root = std::move(root) };
 | 
						|
}
 | 
						|
 | 
						|
template<typename TBase>
 | 
						|
[[nodiscard]]
 | 
						|
MappingBuilder<TBase> operator|(TBase other, MappingOptions options) noexcept
 | 
						|
{
 | 
						|
    return {.root = std::move(options.root), .base = std::move(other) };
 | 
						|
}
 | 
						|
}
 | 
						|
} // namespace mijin
 | 
						|
 | 
						|
#endif // !defined(MIJIN_VIRTUAL_FILESYSTEM_MAPPING_HPP_INCLUDED)
 |