50 constexpr URL()
noexcept =
default;
51 constexpr URL(
URL const&)
noexcept =
default;
52 constexpr URL(
URL&&)
noexcept =
default;
53 constexpr URL& operator=(
URL const&)
noexcept =
default;
54 constexpr URL& operator=(
URL&&)
noexcept =
default;
59 static std::string make_file_url_string(std::filesystem::path
const& path)
63 hilet root_name = path.root_name().generic_string();
64 if (root_name.empty()) {
66 if (not path.root_directory().empty()) {
68 r +=
"file:" + path.root_directory().generic_string();
74 }
else if (
hilet i = root_name.find(
':'); i != std::string::npos) {
77 r +=
"file:///" + root_name + path.root_directory().generic_string();
79 throw url_error(
"Paths containing a device are not allowed to be converted to a URL.");
83 r +=
"file://" + root_name + path.root_directory().generic_string();
84 if (not path.root_directory().empty()) {
85 throw url_error(
"Invalid path contains server name without a root directory.");
89 return r + path.relative_path().generic_string();
92 explicit URL(std::filesystem::path
const& path) :
URI(make_file_url_string(path)) {}
94 constexpr void static validate_file_segment(std::string_view segment)
96 for (
auto c : segment) {
97 if (c ==
'/' or c ==
'\\') {
98 throw url_error(
"Filename server name may not contain slash or back-slash.");
103 constexpr void static validate_file_server(std::string_view server)
105 for (
auto c : server) {
106 if (c ==
'/' or c ==
'\\') {
107 throw url_error(
"Filename segments may not contain slash or back-slash.");
120 throw url_error(
"URL::generic_path() is only valid on a file: scheme URL");
125 hilet first = p.begin();
126 hilet last = p.end();
129 auto has_root_name =
false;
133 if (not server.empty() and server !=
"localhost") {
134 validate_file_server(server);
135 has_root_name =
true;
144 hi_axiom(has_root_name ==
false or p.absolute());
146 if (p.double_absolute()) {
150 throw url_error(
"file URL has two server names.");
153 has_root_name =
true;
157 validate_file_server(*it);
163 auto empty_segment =
false;
165 validate_file_segment(*it);
166 empty_segment = it->empty();
168 if (it == first and empty_segment) {
172 }
else if (
auto i = it->find(
':'); i != std::string::npos) {
175 throw url_error(
"file URL contains a device name which is a security issue.");
178 if (has_root_name or p.absolute()) {
181 r += has_root_name ?
'$' :
':';
194 has_root_name =
true;
206 for (; it != last; ++it) {
207 validate_file_segment(*it);
208 empty_segment = it->empty();
213 if (not empty_segment) {
228 if (
auto scheme_ =
scheme()) {
229 if (scheme_ ==
"resource") {
230 return URL::url_from_resource_directory() / *
this;
231 }
else if (scheme_ ==
"file") {
234 throw url_error(
"URL can not be converted to a filesystem path.");
241 operator std::filesystem::path()
const
251 [[nodiscard]]
constexpr friend URL operator/(
URL const& base,
URI const& ref)
noexcept
253 return URL{up_cast<URI const&>(base) / ref};
256 [[nodiscard]]
constexpr friend URL operator/(
URL const& base, std::string_view ref)
noexcept
258 return URL{up_cast<URI const&>(base) / ref};
261 [[nodiscard]]
static URL url_from_current_working_directory() noexcept;
262 [[nodiscard]] static URL url_from_resource_directory() noexcept;
263 [[nodiscard]] static URL url_from_executable_directory() noexcept;
264 [[nodiscard]] static URL url_from_executable_file() noexcept;
265 [[nodiscard]] static URL url_from_application_data_directory() noexcept;
266 [[nodiscard]] static URL url_from_application_log_directory() noexcept;
267 [[nodiscard]] static URL url_from_system_font_directory() noexcept;
268 [[nodiscard]] static URL url_from_application_preferences_file() noexcept;