Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
asset_path.hpp
Go to the documentation of this file.
1#pragma once
2
4
5#include <string_view>
6
7namespace pulp::timeline {
8
12
15inline bool package_relative_path_is_lexically_safe(std::string_view path) noexcept {
16 if (path.empty() || path.find('\0') != std::string_view::npos || path.front() == '/' ||
17 path.front() == '\\')
18 return false;
19 const auto ascii_alpha = [](char value) noexcept {
20 return (value >= 'A' && value <= 'Z') || (value >= 'a' && value <= 'z');
21 };
22 if (path.size() >= 2 && ascii_alpha(path.front()) && path[1] == ':')
23 return false;
24
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] != '\\')
28 continue;
29 if (path.substr(component_begin, index - component_begin) == "..")
30 return false;
31 component_begin = index + 1;
32 }
33 return true;
34}
35
38inline bool package_relative_path_is_portable(std::string_view path) noexcept {
40 path.find('\\') != std::string_view::npos)
41 return false;
42
43 const auto ascii_upper = [](char value) noexcept {
44 return value >= 'a' && value <= 'z' ? static_cast<char>(value - ('a' - 'A')) : value;
45 };
46 const auto equals_ascii_case_insensitive = [&](std::string_view lhs,
47 std::string_view rhs) noexcept {
48 if (lhs.size() != rhs.size())
49 return false;
50 for (std::size_t index = 0; index < lhs.size(); ++index)
51 if (ascii_upper(lhs[index]) != rhs[index])
52 return false;
53 return true;
54 };
55 const auto windows_component_is_safe = [&](std::string_view component) noexcept {
56 if (component.empty() || component == "." || component == ".." || component.back() == '.' ||
57 component.back() == ' ')
58 return false;
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 == '*')
63 return false;
64 }
65
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$"))
74 return false;
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)
86 return false;
87 }
88 return true;
89 };
90
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] != '/')
94 continue;
95 if (!windows_component_is_safe(path.substr(component_begin, index - component_begin)))
96 return false;
97 component_begin = index + 1;
98 }
99 return true;
100}
101
103
104} // namespace pulp::timeline
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
Definition program_compiler.hpp:18
bool is_valid_utf8(std::string_view value) noexcept
Validates a complete byte sequence as UTF-8 without throwing.