mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-29 15:51:02 +00:00
Implement root fs handling
This commit is contained in:
236
src/windows-emulator/windows_path.hpp
Normal file
236
src/windows-emulator/windows_path.hpp
Normal file
@@ -0,0 +1,236 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <optional>
|
||||
#include <filesystem>
|
||||
#include <utils/string.hpp>
|
||||
|
||||
#include <serialization.hpp>
|
||||
|
||||
namespace windows_path_detail
|
||||
{
|
||||
constexpr std::u16string_view unc_prefix = u"\\??\\";
|
||||
|
||||
inline std::u16string_view strip_unc_prefix(const std::u16string_view path)
|
||||
{
|
||||
if (!path.starts_with(unc_prefix))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
return path.substr(unc_prefix.size());
|
||||
}
|
||||
|
||||
inline bool is_slash(const char16_t chr)
|
||||
{
|
||||
return chr == u'\\' || chr == u'/';
|
||||
}
|
||||
}
|
||||
|
||||
class windows_path
|
||||
{
|
||||
public:
|
||||
windows_path() = default;
|
||||
|
||||
windows_path(const std::filesystem::path& path)
|
||||
{
|
||||
const auto full_path = path.u16string();
|
||||
const auto canonical_path = windows_path_detail::strip_unc_prefix(full_path);
|
||||
|
||||
std::u16string folder{};
|
||||
|
||||
for (const auto chr : canonical_path)
|
||||
{
|
||||
if (chr == u':' && this->folders_.empty() && !this->drive_.has_value() && folder.size() == 1)
|
||||
{
|
||||
this->drive_ = static_cast<char>(folder[0]);
|
||||
folder.clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (windows_path_detail::is_slash(chr))
|
||||
{
|
||||
if (folder.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
this->folders_.push_back(std::move(folder));
|
||||
folder = {};
|
||||
continue;
|
||||
}
|
||||
|
||||
folder.push_back(chr);
|
||||
}
|
||||
|
||||
if (!folder.empty())
|
||||
{
|
||||
this->folders_.push_back(folder);
|
||||
}
|
||||
|
||||
this->canonicalize();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
requires(!std::is_same_v<T, windows_path> && !std::is_same_v<T, std::filesystem::path>)
|
||||
windows_path(T&& path_like)
|
||||
: windows_path(std::filesystem::path(std::forward<T>(path_like)))
|
||||
{
|
||||
}
|
||||
|
||||
windows_path(const std::optional<char> drive, std::list<std::u16string> folders)
|
||||
: drive_(drive),
|
||||
folders_(std::move(folders))
|
||||
{
|
||||
this->canonicalize();
|
||||
}
|
||||
|
||||
bool is_absolute() const
|
||||
{
|
||||
return this->drive_.has_value();
|
||||
}
|
||||
|
||||
bool is_relative() const
|
||||
{
|
||||
return !this->is_absolute();
|
||||
}
|
||||
|
||||
std::u16string u16string() const
|
||||
{
|
||||
std::u16string path{};
|
||||
if (this->drive_)
|
||||
{
|
||||
path.push_back(static_cast<char16_t>(*this->drive_));
|
||||
path.push_back(u':');
|
||||
}
|
||||
|
||||
for (const auto& folder : this->folders_)
|
||||
{
|
||||
if (!path.empty())
|
||||
{
|
||||
path.push_back(u'\\');
|
||||
}
|
||||
|
||||
path.append(folder);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string string() const
|
||||
{
|
||||
return u16_to_u8(this->u16string());
|
||||
}
|
||||
|
||||
std::u16string to_unc_path() const
|
||||
{
|
||||
if (this->is_relative())
|
||||
{
|
||||
return this->u16string();
|
||||
}
|
||||
|
||||
return std::u16string(windows_path_detail::unc_prefix) + this->u16string();
|
||||
}
|
||||
|
||||
std::filesystem::path to_portable_path() const
|
||||
{
|
||||
std::u16string path{};
|
||||
if (this->drive_)
|
||||
{
|
||||
path.push_back(static_cast<char16_t>(*this->drive_));
|
||||
}
|
||||
|
||||
for (const auto& folder : this->folders_)
|
||||
{
|
||||
if (!path.empty())
|
||||
{
|
||||
path.push_back(u'/');
|
||||
}
|
||||
|
||||
path.append(folder);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
windows_path operator/(const windows_path& path) const
|
||||
{
|
||||
if (path.is_absolute())
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
auto folders = this->folders_;
|
||||
|
||||
for (const auto& folder : path.folders_)
|
||||
{
|
||||
folders.push_back(folder);
|
||||
}
|
||||
|
||||
return {this->drive_, std::move(folders)};
|
||||
}
|
||||
|
||||
windows_path& operator/=(const windows_path& path)
|
||||
{
|
||||
*this = *this / path;
|
||||
return *this;
|
||||
}
|
||||
|
||||
windows_path parent() const
|
||||
{
|
||||
auto folders = this->folders_;
|
||||
if (!folders.empty())
|
||||
{
|
||||
folders.pop_back();
|
||||
}
|
||||
|
||||
return {this->drive_, std::move(folders)};
|
||||
}
|
||||
|
||||
void serialize(utils::buffer_serializer& buffer) const
|
||||
{
|
||||
buffer.write_optional(this->drive_);
|
||||
buffer.write_list(this->folders_);
|
||||
}
|
||||
|
||||
void deserialize(utils::buffer_deserializer& buffer)
|
||||
{
|
||||
buffer.read_optional(this->drive_);
|
||||
buffer.read_list(this->folders_);
|
||||
}
|
||||
|
||||
bool operator==(const windows_path& other) const
|
||||
{
|
||||
return this->drive_ == other.drive_ && this->folders_ == other.folders_;
|
||||
}
|
||||
|
||||
bool operator!=(const windows_path& other) const
|
||||
{
|
||||
return !this->operator==(other);
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return !this->is_relative() && this->folders_.empty();
|
||||
}
|
||||
|
||||
private:
|
||||
std::optional<char> drive_{};
|
||||
std::list<std::u16string> folders_{};
|
||||
|
||||
void canonicalize()
|
||||
{
|
||||
if (this->drive_.has_value())
|
||||
{
|
||||
this->drive_ = utils::string::char_to_lower(*this->drive_);
|
||||
}
|
||||
|
||||
for (auto& folder : this->folders_)
|
||||
{
|
||||
for (auto& chr : folder)
|
||||
{
|
||||
chr = utils::string::char_to_lower(chr);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user