浏览代码

feat: implmenet uri-reference and iri-reference

Sam Jaffe 7 月之前
父节点
当前提交
c2dedc8efe
共有 1 个文件被更改,包括 43 次插入16 次删除
  1. 43 16
      include/jvalidate/format.h

+ 43 - 16
include/jvalidate/format.h

@@ -34,6 +34,7 @@ bool date_time(std::string_view dt);
 bool duration(std::string_view dur);
 
 template <typename CharT = char> bool uri(std::basic_string_view<CharT> uri);
+template <typename CharT = char> bool uri_reference(std::basic_string_view<CharT> uri);
 bool uuid(std::string_view id);
 template <typename CharT = char> bool hostname(std::basic_string_view<CharT> name);
 
@@ -85,6 +86,7 @@ inline bool is_leapsecond(std::tm tm) {
 #endif
 }
 
+// https://www.rfc-editor.org/rfc/rfc6570.html#section-1.5
 inline bool is_uschar(int c) {
   using P = std::pair<int, int>;
   constexpr std::array data{
@@ -137,6 +139,19 @@ template <typename CharT> inline bool is_uri_authority(std::basic_string_view<Ch
   }
   return ipv4(to_u8(uri)) || hostname(uri);
 }
+
+template <typename CharT> bool test_uri_part(std::basic_string_view<CharT> & uri, char delim) {
+  size_t const pos = uri.find(delim);
+  if (pos == uri.npos) {
+    return true;
+  }
+  auto part = uri.substr(pos + 1);
+  uri = uri.substr(0, pos);
+  for (size_t pos = 0; pos < part.size(); ++pos) {
+    RETURN_UNLESS(detail::is_pchar(part, pos, ":@/?"), false);
+  }
+  return true;
+};
 }
 
 namespace jvalidate::format {
@@ -182,18 +197,6 @@ inline bool date_time(std::string_view dt) {
 
 template <typename CharT> inline bool uri(std::basic_string_view<CharT> uri) {
   using delim = detail::char_delimiters<CharT>;
-  auto test_uri_part = [&uri](char delim) {
-    size_t const pos = uri.find(delim);
-    if (pos == uri.npos) {
-      return true;
-    }
-    auto part = uri.substr(pos + 1);
-    uri = uri.substr(0, pos);
-    for (size_t pos = 0; pos < part.size(); ++pos) {
-      RETURN_UNLESS(detail::is_pchar(part, pos, ":@/?"), false);
-    }
-    return true;
-  };
 
   // https://www.rfc-editor.org/rfc/rfc3986.html#appendix-A
   if (size_t const pos = uri.find(':'); pos != uri.npos) {
@@ -206,8 +209,32 @@ template <typename CharT> inline bool uri(std::basic_string_view<CharT> uri) {
     return false;
   }
 
-  RETURN_UNLESS(test_uri_part('#'), false);
-  RETURN_UNLESS(test_uri_part('?'), false);
+  RETURN_UNLESS(detail::test_uri_part(uri, '#'), false);
+  RETURN_UNLESS(detail::test_uri_part(uri, '?'), false);
+
+  auto path = uri;
+  if (uri.starts_with(delim::double_slash)) {
+    uri.remove_prefix(2);
+    path = uri.substr(std::min(uri.size(), uri.find('/')));
+    uri.remove_suffix(path.size());
+    RETURN_UNLESS(detail::is_uri_authority(uri), false);
+  }
+
+  for (size_t i = 0; i < path.size(); ++i) {
+    RETURN_UNLESS(detail::is_pchar(path, i, "/:@"), false);
+  }
+
+  return true;
+}
+
+template <typename CharT> inline bool uri_reference(std::basic_string_view<CharT> uri) {
+  using delim = detail::char_delimiters<CharT>;
+  if (jvalidate::format::uri(uri)) {
+    return true;
+  }
+
+  RETURN_UNLESS(detail::test_uri_part(uri, '#'), false);
+  RETURN_UNLESS(detail::test_uri_part(uri, '?'), false);
 
   auto path = uri;
   if (uri.starts_with(delim::double_slash)) {
@@ -491,13 +518,13 @@ private:
       {"ipv4", &format::ipv4},
       {"ipv6", &format::ipv6},
       {"iri", UTF32(uri)},
-      {"iri-reference", nullptr},
+      {"iri-reference", UTF32(uri_reference)},
       {"json-pointer", CONSTRUCTS(Pointer)},
       {"relative-json-pointer", CONSTRUCTS(RelativePointer)},
       {"regex", nullptr},
       {"time", &format::time},
       {"uri", &format::uri},
-      {"uri-reference", nullptr},
+      {"uri-reference", &format::uri_reference},
       {"uri-template", nullptr},
       {"uuid", &format::uuid},
   };