summaryrefslogtreecommitdiff
path: root/graphics/asymptote/LspCpp/third_party/uri/src/detail
diff options
context:
space:
mode:
Diffstat (limited to 'graphics/asymptote/LspCpp/third_party/uri/src/detail')
-rw-r--r--graphics/asymptote/LspCpp/third_party/uri/src/detail/algorithm.hpp70
-rw-r--r--graphics/asymptote/LspCpp/third_party/uri/src/detail/algorithm_find.hpp79
-rw-r--r--graphics/asymptote/LspCpp/third_party/uri/src/detail/algorithm_split.hpp75
-rw-r--r--graphics/asymptote/LspCpp/third_party/uri/src/detail/grammar.hpp124
-rw-r--r--graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_advance_parts.cpp78
-rw-r--r--graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_advance_parts.hpp20
-rw-r--r--graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_normalize.cpp74
-rw-r--r--graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_normalize.hpp20
-rw-r--r--graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_parse.cpp384
-rw-r--r--graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_parse.hpp20
-rw-r--r--graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_parse_authority.cpp116
-rw-r--r--graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_parse_authority.hpp20
-rw-r--r--graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_percent_encode.hpp80
-rw-r--r--graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_resolve.cpp88
-rw-r--r--graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_resolve.hpp22
15 files changed, 1270 insertions, 0 deletions
diff --git a/graphics/asymptote/LspCpp/third_party/uri/src/detail/algorithm.hpp b/graphics/asymptote/LspCpp/third_party/uri/src/detail/algorithm.hpp
new file mode 100644
index 0000000000..6db27e4870
--- /dev/null
+++ b/graphics/asymptote/LspCpp/third_party/uri/src/detail/algorithm.hpp
@@ -0,0 +1,70 @@
+// Copyright 2016 Glyn Matthews.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef NETWORK_DETAIL_RANGE_INC
+#define NETWORK_DETAIL_RANGE_INC
+
+#include <algorithm>
+#include <iterator>
+#include <utility>
+#include <string>
+#include <cctype>
+#include <locale>
+
+namespace network {
+namespace detail {
+template <class Rng, class Pred>
+inline void for_each(Rng &rng, Pred &&pred) {
+ std::for_each(std::begin(rng), std::end(rng), pred);
+}
+
+template <class Rng, class Iter, class Pred>
+inline void transform(Rng &rng, Iter out, Pred &&pred) {
+ std::transform(std::begin(rng), std::end(rng), out, pred);
+}
+
+template <class Rng>
+inline typename Rng::difference_type distance(Rng &rng) {
+ return std::distance(std::begin(rng), std::end(rng));
+}
+
+template <class Rng1, class Rng2>
+inline bool equal(const Rng1 &rng1, const Rng2 &rng2) {
+ return std::equal(std::begin(rng1), std::end(rng1), std::begin(rng2));
+}
+
+template <class Rng, class Pred>
+inline void remove_erase_if(Rng &rng, Pred &&pred) {
+ auto first = std::begin(rng), last = std::end(rng);
+ auto it = std::remove_if(first, last, pred);
+ rng.erase(it, last);
+}
+
+inline std::string trim_front(const std::string &str) {
+ auto first = std::begin(str), last = std::end(str);
+ auto it = std::find_if(
+ first, last, [](char ch) { return !std::isspace(ch, std::locale()); });
+ return std::string(it, last);
+}
+
+inline std::string trim_back(const std::string &str) {
+ using reverse_iterator = std::reverse_iterator<std::string::const_iterator>;
+
+ auto first = reverse_iterator(std::end(str)),
+ last = reverse_iterator(std::begin(str));
+ auto it = std::find_if(
+ first, last, [](char ch) { return !std::isspace(ch, std::locale()); });
+ std::string result(it, last);
+ std::reverse(std::begin(result), std::end(result));
+ return result;
+}
+
+inline std::string trim_copy(const std::string &str) {
+ return trim_back(trim_front(str));
+}
+} // namespace detail
+} // namespace network
+
+#endif // NETWORK_DETAIL_RANGE_INC
diff --git a/graphics/asymptote/LspCpp/third_party/uri/src/detail/algorithm_find.hpp b/graphics/asymptote/LspCpp/third_party/uri/src/detail/algorithm_find.hpp
new file mode 100644
index 0000000000..4d8b99602b
--- /dev/null
+++ b/graphics/asymptote/LspCpp/third_party/uri/src/detail/algorithm_find.hpp
@@ -0,0 +1,79 @@
+/**
+ * Search algorithms
+ * @author Lobaskin Vasily
+ * @data 31 March 2020
+ * @copyright Boost Software License, Version 1.0
+ */
+
+#pragma once
+
+#include <cstddef>
+
+namespace network {
+namespace algorithm {
+
+template <typename IteratorBegT, typename IteratorEndT, typename RangeT>
+IteratorBegT find_nth(IteratorBegT iteratorBeg, IteratorEndT iteratorEnd,
+ RangeT symbol, std::size_t pos) {
+ static_assert(std::is_same<IteratorBegT, IteratorEndT>::value,
+ "Iterator types are different");
+
+ if (iteratorBeg > iteratorEnd) {
+ std::swap(iteratorBeg, iteratorEnd);
+ }
+
+ std::size_t currentPos = -1;
+ while (iteratorBeg != iteratorEnd) {
+ if (*iteratorBeg == symbol) {
+ ++currentPos;
+ if (currentPos == pos) break;
+ }
+ ++iteratorBeg;
+ }
+
+ return iteratorBeg;
+}
+
+template <typename IteratorBegT, typename IteratorEndT, typename ConditionT>
+bool all(IteratorBegT iteratorBeg, IteratorEndT iteratorEnd,
+ ConditionT &&condition) {
+ static_assert(std::is_same<IteratorBegT, IteratorEndT>::value,
+ "Iterator types are different");
+
+ if (iteratorBeg > iteratorEnd) {
+ std::swap(iteratorBeg, iteratorEnd);
+ }
+
+ while (iteratorBeg != iteratorEnd) {
+ if (!condition(*iteratorBeg)) return false;
+
+ ++iteratorBeg;
+ }
+
+ return true;
+}
+
+template <typename ContainerT, typename RangeT>
+typename ContainerT::iterator find_nth(ContainerT &str, RangeT symbol,
+ std::size_t pos) {
+ return algorithm::find_nth(str.begin(), str.end(), symbol, pos);
+}
+
+template <typename ContainerT, typename RangeT>
+typename ContainerT::iterator find_last(ContainerT &str, RangeT symbol) {
+ auto iter = algorithm::find_nth(str.rbegin(), str.rend(), symbol, 0);
+ if (iter == str.rend()) {
+ return str.end();
+ }
+
+ return (++iter).base();
+}
+
+template <typename ContainerT, typename ConditionT>
+bool all(ContainerT const &container, ConditionT &&condition) {
+ return all(container.cbegin(), container.cend(),
+ std::forward<ConditionT>(condition));
+}
+
+} // namespace algorithm
+} // namespace network \ No newline at end of file
diff --git a/graphics/asymptote/LspCpp/third_party/uri/src/detail/algorithm_split.hpp b/graphics/asymptote/LspCpp/third_party/uri/src/detail/algorithm_split.hpp
new file mode 100644
index 0000000000..d6de14543a
--- /dev/null
+++ b/graphics/asymptote/LspCpp/third_party/uri/src/detail/algorithm_split.hpp
@@ -0,0 +1,75 @@
+/**
+ * Search algorithms
+ * @author Lobaskin Vasily
+ * @data 31 March 2020
+ * @copyright Boost Software License, Version 1.0
+ */
+
+#include <type_traits>
+
+namespace network {
+namespace algorithm {
+
+template <typename ContainerT, class SequenceT, typename SplitterT,
+ typename std::enable_if<std::is_fundamental<SplitterT>::value>::type
+ * = nullptr>
+bool split(ContainerT &container, SequenceT const &str, SplitterT symbol) {
+ using PartT = typename ContainerT::value_type;
+ static_assert(std::is_same<typename SequenceT::value_type, SplitterT>::value,
+ "Splitter type doesn't match sequence inner type");
+
+ std::size_t sequenceStart = 0;
+ for (std::size_t i = 0, len = str.size(); i <= len; ++i) {
+ if (str[i] != symbol && i != len) continue;
+
+ std::size_t substrLen = i - sequenceStart;
+ if (substrLen > 0) {
+ PartT part{str.cbegin() + sequenceStart, str.cbegin() + i};
+ container.emplace_back(std::move(part));
+ } else {
+ container.emplace_back(PartT{});
+ }
+ sequenceStart = i + 1;
+ }
+
+ return true;
+}
+
+template <typename ContainerT, class SequenceT, typename SplitterT,
+ typename std::enable_if<!std::is_fundamental<SplitterT>::value>::type
+ * = nullptr>
+bool split(ContainerT &container, SequenceT const &str, SplitterT splitter) {
+ using PartT = typename ContainerT::value_type;
+ static_assert(
+ std::is_same<typename ContainerT::value_type, std::string>::value,
+ "Invalid container type, only string is supported");
+
+ bool isEqual = false;
+ std::size_t sequenceLen = splitter.size();
+ std::size_t sequenceStart = 0;
+ for (std::size_t i = 0, len = str.size(); i <= len; ++i) {
+ isEqual = true;
+ for (std::size_t j = 0; j < sequenceLen; ++j) {
+ if (str[i + j] != splitter[j]) {
+ isEqual = false;
+ break;
+ }
+ }
+ if (!isEqual && i != len) continue;
+
+ std::size_t substrLen = i - sequenceStart;
+ if (substrLen > 0) {
+ PartT part{str.cbegin() + sequenceStart, str.cbegin() + i};
+ container.emplace_back(std::move(part));
+ } else {
+ container.emplace_back(PartT{});
+ }
+ sequenceStart = i + sequenceLen;
+ i += sequenceLen - 1;
+ }
+
+ return true;
+}
+
+} // namespace algorithm
+} // namespace network
diff --git a/graphics/asymptote/LspCpp/third_party/uri/src/detail/grammar.hpp b/graphics/asymptote/LspCpp/third_party/uri/src/detail/grammar.hpp
new file mode 100644
index 0000000000..7630b4ca80
--- /dev/null
+++ b/graphics/asymptote/LspCpp/third_party/uri/src/detail/grammar.hpp
@@ -0,0 +1,124 @@
+// Copyright 2016 Glyn Matthews.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef NETWORK_DETAIL_URI_GRAMMAR_INC
+#define NETWORK_DETAIL_URI_GRAMMAR_INC
+
+#include <network/string_view.hpp>
+#include <cstdlib>
+#include <locale>
+#include <cstring>
+#include <string>
+
+namespace network {
+namespace detail {
+inline bool isalnum(string_view::const_iterator &it,
+ string_view::const_iterator last) {
+ if (it != last) {
+ if (std::isalnum(*it, std::locale::classic())) {
+ ++it;
+ return true;
+ }
+ }
+ return false;
+}
+
+inline bool isdigit(string_view::const_iterator &it,
+ string_view::const_iterator last) {
+ if (it != last) {
+ if (std::isdigit(*it, std::locale::classic())) {
+ ++it;
+ return true;
+ }
+ }
+ return false;
+}
+
+inline bool is_in(string_view::const_iterator &it,
+ string_view::const_iterator last, const char *chars) {
+ if (it != last) {
+ auto length = std::strlen(chars);
+ for (std::size_t i = 0; i < length; ++i) {
+ if (*it == chars[i]) {
+ ++it;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+inline bool is_sub_delim(string_view::const_iterator &it,
+ string_view::const_iterator last) {
+ return is_in(it, last, "!$&'()*+,;=");
+}
+
+inline bool is_ucschar(string_view::const_iterator &it,
+ string_view::const_iterator last) {
+ if (it == last) {
+ return false;
+ }
+
+ return false;
+}
+
+inline bool is_private(string_view::const_iterator &it,
+ string_view::const_iterator last) {
+ return false;
+}
+
+inline bool is_unreserved(string_view::const_iterator &it,
+ string_view::const_iterator last) {
+ return isalnum(it, last) || is_in(it, last, "-._~");
+}
+
+inline bool is_pct_encoded(string_view::const_iterator &it,
+ string_view::const_iterator last) {
+ if (it == last) {
+ return false;
+ }
+
+ string_view::const_iterator it_copy = it;
+
+ if (*it_copy == '%') {
+ ++it_copy;
+ if (it_copy == last) {
+ return false;
+ }
+ }
+
+ if (std::isxdigit(*it_copy, std::locale::classic())) {
+ ++it_copy;
+ if (it_copy == last) {
+ return false;
+ }
+ }
+
+ if (std::isxdigit(*it_copy, std::locale::classic())) {
+ ++it_copy;
+ it = it_copy;
+ return true;
+ }
+
+ return false;
+}
+
+inline bool is_pchar(string_view::const_iterator &it,
+ string_view::const_iterator last) {
+ return is_unreserved(it, last) || is_pct_encoded(it, last) ||
+ is_sub_delim(it, last) || is_in(it, last, ":@") ||
+ is_ucschar(it, last);
+}
+
+inline bool is_valid_port(string_view::const_iterator it) {
+ const char *port_first = &(*it);
+ char *port_last = 0;
+ unsigned long value = std::strtoul(port_first, &port_last, 10);
+ return (value < std::numeric_limits<unsigned short>::max());
+}
+} // namespace detail
+} // namespace network
+
+#endif // NETWORK_DETAIL_URI_GRAMMAR_INC
diff --git a/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_advance_parts.cpp b/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_advance_parts.cpp
new file mode 100644
index 0000000000..7fe35a1c08
--- /dev/null
+++ b/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_advance_parts.cpp
@@ -0,0 +1,78 @@
+// Copyright 2016-2017 Glyn Matthews.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "uri_advance_parts.hpp"
+#include <iterator>
+#include <utility>
+#include <limits>
+
+namespace network_detail = network::detail;
+using network::string_view;
+using network::detail::uri_part;
+
+namespace {
+template <class Iterator>
+uri_part copy_part(Iterator first, Iterator last,
+ string_view::const_iterator &it) {
+ auto part_first = it;
+ std::advance(it, std::distance(first, last));
+ return network_detail::uri_part(part_first, it);
+}
+} // namespace
+
+uri_part network_detail::copy_part(const std::string &uri,
+ string_view::const_iterator &it) {
+ return ::copy_part(std::begin(uri), std::end(uri), it);
+}
+
+void network_detail::advance_parts(string_view uri_view, uri_parts &parts,
+ const uri_parts &existing_parts) {
+ auto first = std::begin(uri_view);
+
+ auto it = first;
+ if (auto scheme = existing_parts.scheme) {
+ parts.scheme = ::copy_part(std::begin(*scheme), std::end(*scheme), it);
+
+ // ignore : for all URIs
+ if (*it == ':') {
+ ++it;
+ }
+
+ // ignore // for hierarchical URIs
+ if (existing_parts.hier_part.host) {
+ std::advance(it, 2);
+ }
+ }
+
+ if (auto user_info = existing_parts.hier_part.user_info) {
+ parts.hier_part.user_info =
+ ::copy_part(std::begin(*user_info), std::end(*user_info), it);
+ ++it; // ignore @
+ }
+
+ if (auto host = existing_parts.hier_part.host) {
+ parts.hier_part.host = ::copy_part(std::begin(*host), std::end(*host), it);
+ }
+
+ if (auto port = existing_parts.hier_part.port) {
+ ++it; // ignore :
+ parts.hier_part.port = ::copy_part(std::begin(*port), std::end(*port), it);
+ }
+
+ if (auto path = existing_parts.hier_part.path) {
+ parts.hier_part.path = ::copy_part(std::begin(*path), std::end(*path), it);
+ }
+
+ if (auto query = existing_parts.query) {
+ ++it; // ignore ?
+ parts.query = ::copy_part(std::begin(*query), std::end(*query), it);
+ }
+
+ if (auto fragment = existing_parts.fragment) {
+ ++it; // ignore #
+ parts.fragment =
+ ::copy_part(std::begin(*fragment), std::end(*fragment), it);
+ }
+}
diff --git a/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_advance_parts.hpp b/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_advance_parts.hpp
new file mode 100644
index 0000000000..6b3eb7e380
--- /dev/null
+++ b/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_advance_parts.hpp
@@ -0,0 +1,20 @@
+// Copyright 2013-2016 Glyn Matthews.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef NETWORK_DETAIL_URI_ADVANCE_INC
+#define NETWORK_DETAIL_URI_ADVANCE_INC
+
+#include <network/uri/detail/uri_parts.hpp>
+
+namespace network {
+namespace detail {
+uri_part copy_part(const std::string &part, string_view::const_iterator &it);
+
+void advance_parts(string_view uri_view, uri_parts &parts,
+ const uri_parts &existing_parts);
+} // namespace detail
+} // namespace network
+
+#endif // NETWORK_DETAIL_URI_ADVANCE_INC
diff --git a/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_normalize.cpp b/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_normalize.cpp
new file mode 100644
index 0000000000..de8c4da610
--- /dev/null
+++ b/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_normalize.cpp
@@ -0,0 +1,74 @@
+// Copyright 2013-2016 Glyn Matthews.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "uri_normalize.hpp"
+#include "uri_percent_encode.hpp"
+#include "algorithm.hpp"
+#include "algorithm_split.hpp"
+#include <iterator>
+#include <vector>
+
+using namespace network::algorithm;
+using network::string_view;
+using network::uri_comparison_level;
+namespace network_detail = network::detail;
+
+std::string network_detail::normalize_path_segments(string_view path) {
+ std::string result;
+
+ if (!path.empty()) {
+ std::vector<std::string> path_segments;
+ split(path_segments, path, '/');
+
+ bool last_segment_is_slash = path_segments.back().empty();
+ std::vector<std::string> normalized_segments;
+ for (const auto &segment : path_segments) {
+ if (segment.empty() || (segment == ".")) {
+ continue;
+ } else if (segment == "..") {
+ if (normalized_segments.empty()) {
+ throw uri_builder_error();
+ }
+ normalized_segments.pop_back();
+ } else {
+ normalized_segments.push_back(segment);
+ }
+ }
+
+ for (const auto &segment : normalized_segments) {
+ result += "/" + segment;
+ }
+
+ if (last_segment_is_slash) {
+ result += "/";
+ }
+ }
+
+ if (result.empty()) {
+ result = "/";
+ }
+
+ return result;
+}
+
+std::string network_detail::normalize_path(string_view path,
+ uri_comparison_level level) {
+ auto result = path.to_string();
+
+ if (uri_comparison_level::syntax_based == level) {
+ // case normalization
+ for_each(result, percent_encoded_to_upper<std::string>());
+
+ // % encoding normalization
+ result.erase(detail::decode_encoded_unreserved_chars(std::begin(result),
+ std::end(result)),
+ std::end(result));
+
+ // % path segment normalization
+ result = normalize_path_segments(result);
+ }
+
+ return result;
+}
diff --git a/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_normalize.hpp b/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_normalize.hpp
new file mode 100644
index 0000000000..3c2e03b11d
--- /dev/null
+++ b/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_normalize.hpp
@@ -0,0 +1,20 @@
+// Copyright 2013-2016 Glyn Matthews.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef NETWORK_DETAIL_NORMALIZE_INC
+#define NETWORK_DETAIL_NORMALIZE_INC
+
+#include <network/uri/uri.hpp>
+#include <network/string_view.hpp>
+
+namespace network {
+namespace detail {
+std::string normalize_path_segments(string_view path);
+
+std::string normalize_path(string_view path, uri_comparison_level level);
+} // namespace detail
+} // namespace network
+
+#endif // NETWORK_DETAIL_NORMALIZE_INC
diff --git a/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_parse.cpp b/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_parse.cpp
new file mode 100644
index 0000000000..7f771480db
--- /dev/null
+++ b/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_parse.cpp
@@ -0,0 +1,384 @@
+// Copyright 2016-2017 Glyn Matthews.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "uri_parse.hpp"
+#include <iterator>
+#include <limits>
+#include "grammar.hpp"
+#include <network/uri/detail/uri_parts.hpp>
+
+namespace network {
+namespace detail {
+namespace {
+enum class uri_state { scheme, hier_part, query, fragment };
+
+enum class hier_part_state {
+ first_slash,
+ second_slash,
+ authority,
+ host,
+ host_ipv6,
+ port,
+ path
+};
+
+bool validate_scheme(string_view::const_iterator &it,
+ string_view::const_iterator last) {
+ if (it == last) {
+ return false;
+ }
+
+ // The first character must be a letter
+ if (!std::isalpha(*it, std::locale("C"))) {
+ return false;
+ }
+ ++it;
+
+ while (it != last) {
+ if (*it == ':') {
+ break;
+ } else if (!isalnum(it, last) && !is_in(it, last, "+-.")) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool validate_user_info(string_view::const_iterator it,
+ string_view::const_iterator last) {
+ while (it != last) {
+ if (!is_unreserved(it, last) && !is_pct_encoded(it, last) &&
+ !is_sub_delim(it, last) && !is_in(it, last, ":")) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool set_host_and_port(string_view::const_iterator first,
+ string_view::const_iterator last,
+ string_view::const_iterator last_colon,
+ uri_parts &parts) {
+ if (first >= last_colon) {
+ parts.hier_part.host = uri_part(first, last);
+ } else {
+ auto port_start = last_colon;
+ ++port_start;
+ parts.hier_part.host = uri_part(first, last_colon);
+ if (!is_valid_port(port_start)) {
+ return false;
+ }
+ parts.hier_part.port = uri_part(port_start, last);
+ }
+ return true;
+}
+
+bool validate_fragment(string_view::const_iterator &it,
+ string_view::const_iterator last) {
+ while (it != last) {
+ if (!is_pchar(it, last) && !is_in(it, last, "?/")) {
+ return false;
+ }
+ }
+ return true;
+}
+} // namespace
+
+bool parse(string_view::const_iterator &it, string_view::const_iterator last,
+ uri_parts &parts) {
+ auto state = uri_state::scheme;
+
+ auto first = it;
+
+ if (it == last) {
+ return false;
+ }
+
+ if (validate_scheme(it, last)) {
+ parts.scheme = uri_part(first, it);
+ // move past the scheme delimiter
+ ++it;
+ state = uri_state::hier_part;
+ } else {
+ return false;
+ }
+
+ // Hierarchical part
+ auto hp_state = hier_part_state::first_slash;
+ // this is used by the user_info/port
+ auto last_colon = first;
+ while (it != last) {
+ if (hp_state == hier_part_state::first_slash) {
+ if (*it == '/') {
+ hp_state = hier_part_state::second_slash;
+ // set the first iterator in case the second slash is not forthcoming
+ first = it;
+ ++it;
+ continue;
+ } else {
+ hp_state = hier_part_state::path;
+ first = it;
+ }
+ } else if (hp_state == hier_part_state::second_slash) {
+ if (*it == '/') {
+ hp_state = hier_part_state::authority;
+ ++it;
+ first = it;
+ continue;
+ } else {
+ // it's a valid URI, and this is the beginning of the path
+ hp_state = hier_part_state::path;
+ }
+ } else if (hp_state == hier_part_state::authority) {
+ if (is_in(first, last, "@:")) {
+ return false;
+ }
+
+ // reset the last colon
+ if (first == it) {
+ last_colon = first;
+ }
+
+ if (*it == '@') {
+ if (!validate_user_info(first, it)) {
+ return false;
+ }
+ parts.hier_part.user_info = uri_part(first, it);
+ hp_state = hier_part_state::host;
+ ++it;
+ first = it;
+
+ if (*first == '[') {
+ // this is an IPv6 address
+ hp_state = hier_part_state::host_ipv6;
+ }
+
+ continue;
+ } else if (*it == '[') {
+ // this is an IPv6 address
+ hp_state = hier_part_state::host_ipv6;
+ first = it;
+ continue;
+ } else if (*it == ':') {
+ last_colon = it;
+ } else if (*it == '/') {
+ // we skipped right past the host and port, and are at the path.
+ if (!set_host_and_port(first, it, last_colon, parts)) {
+ return false;
+ }
+ hp_state = hier_part_state::path;
+ first = it;
+ continue;
+ } else if (*it == '?') {
+ // the path is empty, but valid, and the next part is the query
+ if (!set_host_and_port(first, it, last_colon, parts)) {
+ return false;
+ }
+ parts.hier_part.path = uri_part(it, it);
+ state = uri_state::query;
+ ++it;
+ first = it;
+ break;
+ } else if (*it == '#') {
+ // the path is empty, but valid, and the next part is the fragment
+ if (!set_host_and_port(first, it, last_colon, parts)) {
+ return false;
+ }
+ parts.hier_part.path = uri_part(it, it);
+ state = uri_state::fragment;
+ ++it;
+ first = it;
+ break;
+ }
+ } else if (hp_state == hier_part_state::host) {
+ if (*first == ':') {
+ return false;
+ }
+
+ if (*it == ':') {
+ parts.hier_part.host = uri_part(first, it);
+ hp_state = hier_part_state::port;
+ ++it;
+ first = it;
+ continue;
+ } else if (*it == '/') {
+ parts.hier_part.host = uri_part(first, it);
+ hp_state = hier_part_state::path;
+ first = it;
+ continue;
+ } else if (*it == '?') {
+ // the path is empty, but valid, and the next part is the query
+ parts.hier_part.host = uri_part(first, it);
+ parts.hier_part.path = uri_part(it, it);
+ state = uri_state::query;
+ ++it;
+ first = it;
+ break;
+ } else if (*it == '#') {
+ // the path is empty, but valid, and the next part is the fragment
+ parts.hier_part.host = uri_part(first, it);
+ parts.hier_part.path = uri_part(it, it);
+ state = uri_state::fragment;
+ ++it;
+ first = it;
+ break;
+ }
+ } else if (hp_state == hier_part_state::host_ipv6) {
+ if (*first != '[') {
+ return false;
+ }
+
+ if (*it == ']') {
+ ++it;
+ // Then test if the next part is a host, part, or the end of the file
+ if (it == last) {
+ break;
+ } else if (*it == ':') {
+ parts.hier_part.host = uri_part(first, it);
+ hp_state = hier_part_state::port;
+ ++it;
+ first = it;
+ } else if (*it == '/') {
+ parts.hier_part.host = uri_part(first, it);
+ hp_state = hier_part_state::path;
+ first = it;
+ } else if (*it == '?') {
+ parts.hier_part.host = uri_part(first, it);
+ parts.hier_part.path = uri_part(it, it);
+ state = uri_state::query;
+ ++it;
+ first = it;
+ break;
+ } else if (*it == '#') {
+ parts.hier_part.host = uri_part(first, it);
+ parts.hier_part.path = uri_part(it, it);
+ state = uri_state::fragment;
+ ++it;
+ first = it;
+ break;
+ }
+ continue;
+ }
+ } else if (hp_state == hier_part_state::port) {
+ if (*first == '/') {
+ // the port is empty, but valid
+ if (!is_valid_port(first)) {
+ return false;
+ }
+ parts.hier_part.port = uri_part(first, it);
+
+ // the port isn't set, but the path is
+ hp_state = hier_part_state::path;
+ continue;
+ }
+
+ if (*it == '/') {
+ if (!is_valid_port(first)) {
+ return false;
+ }
+ parts.hier_part.port = uri_part(first, it);
+ hp_state = hier_part_state::path;
+ first = it;
+ continue;
+ } else if (!isdigit(it, last)) {
+ return false;
+ }
+ continue;
+ } else if (hp_state == hier_part_state::path) {
+ if (*it == '?') {
+ parts.hier_part.path = uri_part(first, it);
+ // move past the query delimiter
+ ++it;
+ first = it;
+ state = uri_state::query;
+ break;
+ } else if (*it == '#') {
+ parts.hier_part.path = uri_part(first, it);
+ // move past the fragment delimiter
+ ++it;
+ first = it;
+ state = uri_state::fragment;
+ break;
+ }
+
+ if (!is_pchar(it, last) && !is_in(it, last, "/")) {
+ return false;
+ } else {
+ continue;
+ }
+ }
+
+ ++it;
+ }
+
+ if (state == uri_state::query) {
+ while (it != last) {
+ if (!is_pchar(it, last) && !is_in(it, last, "?/")) {
+ // If this is a fragment, keep going
+ if (*it == '#') {
+ parts.query = uri_part(first, it);
+ // move past the fragment delimiter
+ ++it;
+ first = it;
+ state = uri_state::fragment;
+ break;
+ } else {
+ return false;
+ }
+ }
+ }
+ }
+
+ if (state == uri_state::fragment) {
+ if (!validate_fragment(it, last)) {
+ return false;
+ }
+ }
+
+ // we're done!
+ if (state == uri_state::hier_part) {
+ if (hp_state == hier_part_state::authority) {
+ if (first == last) {
+ return false;
+ }
+
+ if (!set_host_and_port(first, last, last_colon, parts)) {
+ return false;
+ }
+ parts.hier_part.path = uri_part(last, last);
+ } else if (hp_state == hier_part_state::host) {
+ if (first == last) {
+ return false;
+ }
+
+ if (!set_host_and_port(first, last, last_colon, parts)) {
+ return false;
+ }
+ parts.hier_part.path = uri_part(last, last);
+ } else if (hp_state == hier_part_state::host_ipv6) {
+ if (!set_host_and_port(first, last, last_colon, parts)) {
+ return false;
+ }
+ parts.hier_part.path = uri_part(last, last);
+ } else if (hp_state == hier_part_state::port) {
+ if (!is_valid_port(first)) {
+ return false;
+ }
+ parts.hier_part.port = uri_part(first, last);
+ parts.hier_part.path = uri_part(last, last);
+ } else if (hp_state == hier_part_state::path) {
+ parts.hier_part.path = uri_part(first, last);
+ }
+ } else if (state == uri_state::query) {
+ parts.query = uri_part(first, last);
+ } else if (state == uri_state::fragment) {
+ parts.fragment = uri_part(first, last);
+ }
+
+ return true;
+}
+} // namespace detail
+} // namespace network
diff --git a/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_parse.hpp b/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_parse.hpp
new file mode 100644
index 0000000000..5eb5420bd3
--- /dev/null
+++ b/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_parse.hpp
@@ -0,0 +1,20 @@
+// Copyright 2013-2016 Glyn Matthews.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef NETWORK_DETAIL_URI_PARSE_INC
+#define NETWORK_DETAIL_URI_PARSE_INC
+
+#include <network/string_view.hpp>
+
+namespace network {
+namespace detail {
+struct uri_parts;
+
+bool parse(string_view::const_iterator &first, string_view::const_iterator last,
+ uri_parts &parts);
+} // namespace detail
+} // namespace network
+
+#endif // NETWORK_DETAIL_URI_PARSE_INC
diff --git a/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_parse_authority.cpp b/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_parse_authority.cpp
new file mode 100644
index 0000000000..29b7de7f68
--- /dev/null
+++ b/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_parse_authority.cpp
@@ -0,0 +1,116 @@
+// Copyright 2016 Glyn Matthews.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "uri_parse_authority.hpp"
+#include <cstdlib>
+#include <iterator>
+#include <limits>
+#include "grammar.hpp"
+
+namespace network {
+namespace detail {
+namespace {
+enum class authority_state { user_info, host, host_ipv6, port };
+} // namespace
+
+bool parse_authority(string_view::const_iterator &it,
+ string_view::const_iterator last,
+ optional<uri_part> &user_info, optional<uri_part> &host,
+ optional<uri_part> &port) {
+ auto first = it;
+
+ auto state = authority_state::user_info;
+ while (it != last) {
+ if (state == authority_state::user_info) {
+ if (is_in(first, last, "@:")) {
+ return false;
+ }
+
+ if (*it == '@') {
+ user_info = uri_part(first, it);
+ state = authority_state::host;
+ ++it;
+ first = it;
+ continue;
+ } else if (*it == '[') {
+ // this is an IPv6 address
+ state = authority_state::host_ipv6;
+ first = it;
+ continue;
+ } else if (*it == ':') {
+ // this is actually the host, and the next part is expected to be the
+ // port
+ host = uri_part(first, it);
+ state = authority_state::port;
+ ++it;
+ first = it;
+ continue;
+ }
+ } else if (state == authority_state::host) {
+ if (*first == ':') {
+ return false;
+ }
+
+ if (*it == ':') {
+ host = uri_part(first, it);
+ state = authority_state::port;
+ ++it;
+ first = it;
+ continue;
+ }
+ } else if (state == authority_state::host_ipv6) {
+ if (*first != '[') {
+ return false;
+ }
+
+ if (*it == ']') {
+ host = uri_part(first, it);
+ ++it;
+ // Then test if the next part is a host, part, or the end of the file
+ if (it == last) {
+ break;
+ } else if (*it == ':') {
+ host = uri_part(first, it);
+ state = authority_state::port;
+ ++it;
+ first = it;
+ }
+ }
+ } else if (state == authority_state::port) {
+ if (*first == '/') {
+ // the port is empty, but valid
+ port = uri_part(first, it);
+ if (!is_valid_port(std::begin(*port))) {
+ return false;
+ }
+
+ continue;
+ }
+
+ if (!isdigit(it, last)) {
+ return false;
+ }
+ }
+
+ ++it;
+ }
+
+ if (state == authority_state::user_info) {
+ host = uri_part(first, last);
+ } else if (state == authority_state::host) {
+ host = uri_part(first, last);
+ } else if (state == authority_state::host_ipv6) {
+ host = uri_part(first, last);
+ } else if (state == authority_state::port) {
+ port = uri_part(first, last);
+ if (!is_valid_port(std::begin(*port))) {
+ return false;
+ }
+ }
+
+ return true;
+}
+} // namespace detail
+} // namespace network
diff --git a/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_parse_authority.hpp b/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_parse_authority.hpp
new file mode 100644
index 0000000000..df1d7d5b18
--- /dev/null
+++ b/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_parse_authority.hpp
@@ -0,0 +1,20 @@
+// Copyright 2013-2016 Glyn Matthews.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef NETWORK_DETAIL_URI_PARSE_AUTHORITY_INC
+#define NETWORK_DETAIL_URI_PARSE_AUTHORITY_INC
+
+#include <network/uri/detail/uri_parts.hpp>
+
+namespace network {
+namespace detail {
+bool parse_authority(string_view::const_iterator &first,
+ string_view::const_iterator last,
+ optional<uri_part> &user_info, optional<uri_part> &host,
+ optional<uri_part> &port);
+} // namespace detail
+} // namespace network
+
+#endif // NETWORK_DETAIL_URI_PARSE_AUTHORITY_INC
diff --git a/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_percent_encode.hpp b/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_percent_encode.hpp
new file mode 100644
index 0000000000..0f39a4723d
--- /dev/null
+++ b/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_percent_encode.hpp
@@ -0,0 +1,80 @@
+// Copyright 2013-2016 Glyn Matthews.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef NETWORK_DETAIL_URI_PERCENT_ENCODE_INC
+#define NETWORK_DETAIL_URI_PERCENT_ENCODE_INC
+
+#include <string>
+#include <vector>
+#include <locale>
+#include <network/optional.hpp>
+#include <network/uri/detail/decode.hpp>
+
+namespace network {
+namespace detail {
+
+inline optional<char> percent_encode(std::string::const_iterator it) {
+ try {
+ char output = '\0';
+ detail::decode_char(it, &output);
+ return output;
+ } catch (percent_decoding_error &) {
+ return optional<char>();
+ }
+}
+
+template <class String>
+struct percent_encoded_to_upper {
+ percent_encoded_to_upper() : count(0) {}
+
+ void operator()(typename String::value_type &c) {
+ if (c == '%') {
+ count = 2;
+ } else if (count > 0) {
+ c = std::toupper(c, std::locale());
+ --count;
+ }
+ }
+
+ unsigned count;
+};
+
+template <class Iter>
+Iter decode_encoded_unreserved_chars(Iter first, Iter last) {
+ // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ // clang-format off
+ const auto is_unreserved = [](char c) {
+ return std::isalnum(c, std::locale())
+ || '-' == c
+ || '.' == c
+ || '_' == c
+ || '~' == c;
+ };
+ // clang-format on
+
+ auto it = first, it2 = first;
+ while (it != last) {
+ if (*it == '%') {
+ const auto sfirst = it;
+ const auto opt_char = percent_encode(sfirst);
+ if (opt_char && is_unreserved(*opt_char)) {
+ *it2 = *opt_char;
+ ++it;
+ ++it;
+ } else {
+ *it2 = *it;
+ }
+ } else {
+ *it2 = *it;
+ }
+ ++it;
+ ++it2;
+ }
+ return it2;
+}
+} // namespace detail
+} // namespace network
+
+#endif // NETWORK_DETAIL_URI_PERCENT_ENCODE_INC
diff --git a/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_resolve.cpp b/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_resolve.cpp
new file mode 100644
index 0000000000..024ee12603
--- /dev/null
+++ b/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_resolve.cpp
@@ -0,0 +1,88 @@
+// Copyright 2013-2016 Glyn Matthews.
+// Copyright 2013 Hannes Kamecke.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "uri_resolve.hpp"
+#include "algorithm_find.hpp"
+
+using namespace network::algorithm;
+using network::uri;
+using network::string_view;
+namespace network_detail = network::detail;
+
+namespace {
+
+// remove_dot_segments
+inline void remove_last_segment(std::string &path) {
+ while (!path.empty()) {
+ if (path.back() == '/') {
+ path.pop_back();
+ break;
+ }
+ path.pop_back();
+ }
+}
+
+inline bool starts_with(std::string const &str, const char *range) {
+ return str.find(range) == 0;
+}
+
+// implementation of http://tools.ietf.org/html/rfc3986#section-5.2.4
+static std::string remove_dot_segments(std::string input) {
+ std::string result;
+
+ while (!input.empty()) {
+ if (starts_with(input, "../")) {
+ input.erase(0, 3);
+ } else if (starts_with(input, "./")) {
+ input.erase(0, 2);
+ } else if (starts_with(input, "/./")) {
+ input.erase(0, 2);
+ input.front() = '/';
+ } else if (input == "/.") {
+ input.erase(0, 1);
+ input.front() = '/';
+ } else if (starts_with(input, "/../")) {
+ input.erase(0, 3);
+ remove_last_segment(result);
+ } else if (starts_with(input, "/..")) {
+ input.erase(0, 2);
+ input.front() = '/';
+ remove_last_segment(result);
+ } else if (all(input, [](char ch) { return ch == '.'; })) {
+ input.clear();
+ } else {
+ int n = (input.front() == '/') ? 1 : 0;
+ std::string::iterator slash = find_nth(input, '/', n);
+ result.append(std::begin(input), slash);
+ input.erase(std::begin(input), slash);
+ }
+ }
+ return result;
+}
+
+} // namespace
+
+std::string network_detail::remove_dot_segments(string_view path) {
+ return ::remove_dot_segments(path.to_string());
+}
+
+// implementation of http://tools.ietf.org/html/rfc3986#section-5.2.3
+std::string network_detail::merge_paths(const uri &base, const uri &reference) {
+ std::string result;
+
+ if (!base.has_path() || base.path().empty()) {
+ result = "/";
+ } else {
+ const auto &base_path = base.path();
+ auto last_slash = algorithm::find_last(base_path, '/');
+ if (last_slash != base_path.cend()) ++last_slash;
+ result.append(std::begin(base_path), last_slash);
+ }
+ if (reference.has_path()) {
+ result.append(reference.path().to_string());
+ }
+ return remove_dot_segments(string_view(result));
+}
diff --git a/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_resolve.hpp b/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_resolve.hpp
new file mode 100644
index 0000000000..898c6d5423
--- /dev/null
+++ b/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_resolve.hpp
@@ -0,0 +1,22 @@
+// Copyright 2013-2016 Glyn Matthews.
+// Copyright 2013 Hannes Kamecke.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef NETWORK_DETAIL_RESOLVE_INC
+#define NETWORK_DETAIL_RESOLVE_INC
+
+#include <network/uri/uri.hpp>
+
+namespace network {
+namespace detail {
+// implementation of http://tools.ietf.org/html/rfc3986#section-5.2.4
+std::string remove_dot_segments(string_view input);
+
+// implementation of http://tools.ietf.org/html/rfc3986#section-5.2.3
+std::string merge_paths(const uri &base, const uri &reference);
+} // namespace detail
+} // namespace network
+
+#endif // NETWORK_DETAIL_RESOLVE_INC