Program Listing for File navigator.cpp¶
↰ Return to documentation for file (/home/runner/work/Legion-Engine/Legion-Engine/legion/engine/core/filesystem/navigator.cpp
)
#include "navigator.hpp"
#include "detail/strpath_manip.hpp"
#include <core/common/string_extra.hpp>
#include <core/filesystem/provider_registry.hpp>
#include <Optick/optick.h>
namespace legion::core::filesystem {
common::result<navigator::solution,fs_error> navigator::find_solution(const std::string& opt_root_domain) const
{
OPTICK_EVENT();
using common::Err,common::Ok;
std::string root_domain;
std::string to_process;
if(!opt_root_domain.empty())
{
root_domain = opt_root_domain;
to_process = m_path;
} else {
//find root domain
// the syntax for inline root-domains has to be <root-domain>:[/\\]+<rest-of-the-path>
const auto rdIndex = m_path.find_first_of(':');
if(rdIndex == std::string::npos) return Err(legion_fs_error("invalid syntax for path string, no domain delimiter"));
root_domain = m_path.substr(0,rdIndex);
//find the rest of the path ... technically this will resolve //////////lol/test.bin to lol/test.bin just fine,
//but hopefully no one is actually insane enough to mess with such paths
//
//if he/she does, congrats you found a ... "feature"
const auto pIndex = m_path.find_first_not_of("/\\",rdIndex+1);
if(pIndex == std::string::npos) return Err(legion_fs_error("invalid sytax for path string, last domain delimiter not found"));
to_process = m_path.substr(pIndex,std::string::npos);
to_process = strpath_manip::sanitize(to_process);
}
if(root_domain.empty() || to_process.empty()) return Err(legion_fs_error("invalid syntax for path string, one or more properties empty"));
root_domain += std::string(":") + strpath_manip::separator() + strpath_manip::separator();
if(!provider_registry::has_domain(root_domain)) return Err(legion_fs_error(("no start! no such domain: " + root_domain).c_str()));
solution steps{};
auto tokens = common::split_string_at<'\\','/'>(to_process);
std::string previous_domain = root_domain;
std::string domain = root_domain;
filesystem_resolver* resolver;
std::string path_for_resolver;
//get first resolver
//TODO support multiple resolvers
resolver = *provider_registry::domain_get_first_resolver(domain);
for (auto& token : tokens) {
if(previous_domain != domain)
{
previous_domain = domain;
if(!provider_registry::has_domain(domain)) return Err(legion_fs_error(("stop! no such domain: " + domain).c_str()));
//add resolver step
steps.emplace_back(resolver,strpath_manip::sanitize(path_for_resolver));
//get new resolver
resolver = *provider_registry::domain_get_first_resolver(domain);
if(!dynamic_cast<memory_resolver_common_base*>(resolver)) return Err(legion_fs_error("sub domain resolver was not a mem resolver, illegal access"));
path_for_resolver = "";
}
//we sanitized the string prior checking this
//if .. or . still remains, than your path is simply wrong (relative paths to outside or a provider are not allowed!)
if(token.find('.') != std::string::npos)
{
domain = token.substr(token.find_first_of('.'),std::string::npos);
//the file itself is still part of the old resolver
//i.e.: /sandbox/assets/archive.pp.xz -> directory_in_archive/file.png
//where the new domain is ".pp.xz"
path_for_resolver += token;
}
else
{
path_for_resolver += token + resolver->get_delimiter();
}
}
//add final step
steps.emplace_back(resolver,strpath_manip::sanitize(path_for_resolver));
return Ok(steps);
}
}