mirror of
https://github.com/boostorg/quickbook.git
synced 2026-02-02 09:02:15 +00:00
Improved file_path_to_url for windows edge cases
Really not sure about this, but filesystem doesn't have great support anyway[1], and this handles some unusual cases better. [1]: https://svn.boost.org/trac10/ticket/5448
This commit is contained in:
93
src/path.cpp
93
src/path.cpp
@@ -121,44 +121,85 @@ namespace quickbook
|
||||
//
|
||||
// Some info on file URLs at:
|
||||
// https://en.wikipedia.org/wiki/File_URI_scheme
|
||||
std::string file_path_to_url(fs::path const& x)
|
||||
std::string file_path_to_url_impl(fs::path const& x, bool is_dir)
|
||||
{
|
||||
// TODO: Maybe some kind of error if this doesn't understand the path.
|
||||
// TODO: Might need a special cygwin implementation.
|
||||
// TODO: What if x.has_root_name() && !x.has_root_directory()?
|
||||
// TODO: What does Boost.Filesystem do for '//localhost/c:/path'?
|
||||
// Is that event allowed by windows?
|
||||
fs::path::const_iterator it = x.begin(), end = x.end();
|
||||
if (it == end) { return is_dir ? "./" : ""; }
|
||||
|
||||
std::string result;
|
||||
bool sep = false;
|
||||
std::string part;
|
||||
if (x.has_root_name()) {
|
||||
std::string root_name = detail::path_to_generic(x.root_name());
|
||||
// Handle network address (e.g. \\example.com)
|
||||
part = detail::path_to_generic(*it);
|
||||
if (part.size() >= 2 && part[0] == '/' && part[1] == '/') {
|
||||
result = "file:" + detail::escape_uri(part);
|
||||
sep = true;
|
||||
++it;
|
||||
if (it != end && *it == "/") {
|
||||
result += "/";
|
||||
sep = false;
|
||||
++it;
|
||||
}
|
||||
} else {
|
||||
result = "file:///";
|
||||
}
|
||||
|
||||
if (root_name.size() > 2 && root_name[0] == '/' && root_name[1] == '/') {
|
||||
// root_name is a network location.
|
||||
return "file:" + detail::escape_uri(detail::path_to_generic(x));
|
||||
// Handle windows root (e.g. c:)
|
||||
if (it != end) {
|
||||
part = detail::path_to_generic(*it);
|
||||
if (part.size() >= 2 && part[part.size() - 1] == ':') {
|
||||
result += detail::escape_uri(part.substr(0, part.size()- 1));
|
||||
result += ':';
|
||||
sep = false;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
else if (root_name.size() >= 2 && root_name[root_name.size() - 1] == ':') {
|
||||
// root_name is a drive.
|
||||
return "file:///"
|
||||
+ detail::escape_uri(root_name.substr(0, root_name.size() - 1))
|
||||
+ ":/" // Somtimes "|/" is used, to avoid misinterpreting the ':'.
|
||||
+ detail::escape_uri(detail::path_to_generic(x.relative_path()));
|
||||
}
|
||||
else {
|
||||
// Not sure what root_name is.
|
||||
return detail::escape_uri(detail::path_to_generic(x));
|
||||
} else if (x.has_root_directory()) {
|
||||
result = "file://";
|
||||
sep = true;
|
||||
} else if (*it == ".") {
|
||||
result = ".";
|
||||
sep = true;
|
||||
++it;
|
||||
}
|
||||
|
||||
for (;it != end; ++it)
|
||||
{
|
||||
part = detail::path_to_generic(*it);
|
||||
if (part == "/") {
|
||||
result += "/";
|
||||
sep = false;
|
||||
} else if (part == ".") {
|
||||
// If the path has a trailing slash, write it out,
|
||||
// even if is_dir is false.
|
||||
if (sep) {
|
||||
result += "/";
|
||||
sep = false;
|
||||
}
|
||||
} else {
|
||||
if (sep) {
|
||||
result += "/";
|
||||
}
|
||||
result += detail::escape_uri(detail::path_to_generic(*it));
|
||||
sep = true;
|
||||
}
|
||||
}
|
||||
else if (x.has_root_directory()) {
|
||||
return "file://" + detail::escape_uri(detail::path_to_generic(x));
|
||||
}
|
||||
else {
|
||||
return detail::escape_uri(detail::path_to_generic(x));
|
||||
|
||||
if (is_dir && sep) {
|
||||
result += "/";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string file_path_to_url(fs::path const& x) {
|
||||
return file_path_to_url_impl(x, false);
|
||||
}
|
||||
|
||||
std::string dir_path_to_url(fs::path const& x)
|
||||
{
|
||||
return file_path_to_url(x) + "/";
|
||||
return file_path_to_url_impl(x, true);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
Reference in New Issue
Block a user