16 if (path.empty() || path.find(
'\0') != std::string_view::npos || path.front() ==
'/' ||
19 const auto ascii_alpha = [](
char value)
noexcept {
20 return (value >=
'A' && value <=
'Z') || (value >=
'a' && value <=
'z');
22 if (path.size() >= 2 && ascii_alpha(path.front()) && path[1] ==
':')
25 std::size_t component_begin = 0;
26 for (std::size_t index = 0; index <= path.size(); ++index) {
27 if (index != path.size() && path[index] !=
'/' && path[index] !=
'\\')
29 if (path.substr(component_begin, index - component_begin) ==
"..")
31 component_begin = index + 1;
40 path.find(
'\\') != std::string_view::npos)
43 const auto ascii_upper = [](
char value)
noexcept {
44 return value >=
'a' && value <= 'z' ? static_cast<char>(value - (
'a' -
'A')) : value;
46 const auto equals_ascii_case_insensitive = [&](std::string_view lhs,
47 std::string_view rhs)
noexcept {
48 if (lhs.size() != rhs.size())
50 for (std::size_t index = 0; index < lhs.size(); ++index)
51 if (ascii_upper(lhs[index]) != rhs[index])
55 const auto windows_component_is_safe = [&](std::string_view component)
noexcept {
56 if (component.empty() || component ==
"." || component ==
".." || component.back() ==
'.' ||
57 component.back() ==
' ')
59 for (
const auto value : component) {
60 const auto byte =
static_cast<unsigned char>(value);
61 if (
byte < 0x20 || value ==
'<' || value ==
'>' || value ==
':' || value ==
'"' ||
62 value ==
'|' || value ==
'?' || value ==
'*')
66 const auto base = component.substr(0, component.find(
'.'));
67 if (equals_ascii_case_insensitive(base,
"CON") ||
68 equals_ascii_case_insensitive(base,
"PRN") ||
69 equals_ascii_case_insensitive(base,
"AUX") ||
70 equals_ascii_case_insensitive(base,
"NUL") ||
71 equals_ascii_case_insensitive(base,
"CLOCK$") ||
72 equals_ascii_case_insensitive(base,
"CONIN$") ||
73 equals_ascii_case_insensitive(base,
"CONOUT$"))
75 if (base.size() >= 4 && ((ascii_upper(base[0]) ==
'C' && ascii_upper(base[1]) ==
'O' &&
76 ascii_upper(base[2]) ==
'M') ||
77 (ascii_upper(base[0]) ==
'L' && ascii_upper(base[1]) ==
'P' &&
78 ascii_upper(base[2]) ==
'T'))) {
79 const bool ascii_device_digit = base.size() == 4 && base[3] >=
'1' && base[3] <=
'9';
80 const bool superscript_device_digit = base.size() == 5 &&
81 static_cast<unsigned char>(base[3]) == 0xc2 &&
82 (
static_cast<unsigned char>(base[4]) == 0xb9 ||
83 static_cast<unsigned char>(base[4]) == 0xb2 ||
84 static_cast<unsigned char>(base[4]) == 0xb3);
85 if (ascii_device_digit || superscript_device_digit)
91 std::size_t component_begin = 0;
92 for (std::size_t index = 0; index <= path.size(); ++index) {
93 if (index != path.size() && path[index] !=
'/')
95 if (!windows_component_is_safe(path.substr(component_begin, index - component_begin)))
97 component_begin = index + 1;
bool package_relative_path_is_portable(std::string_view path) noexcept
Returns whether a new package-publication path is portable across supported filesystems and cannot be...
Definition asset_path.hpp:38
bool package_relative_path_is_lexically_safe(std::string_view path) noexcept
Returns whether a persisted package-relative locator preserves Timeline's historical lexical contract...
Definition asset_path.hpp:15