180 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			180 lines
		
	
	
		
			4.3 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)
 | |
|     {
 | |
|         if (fileInfo.path.is_absolute())
 | |
|         {
 | |
|             fileInfo.path = fs::relative(fileInfo.path, "/");
 | |
|         }
 | |
|         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.empty() || *path.generic_string().c_str() != '/')
 | |
|     {
 | |
|         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)
 |