diff options
Diffstat (limited to 'graphics/asymptote/LspCpp/third_party/uri/src/detail')
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 |