Kaynağa Gözat

fix: various off-by-one type errors in references, and encoded pointers

Sam Jaffe 1 yıl önce
ebeveyn
işleme
341a408fc2

+ 22 - 7
include/jvalidate/detail/pointer.h

@@ -17,12 +17,29 @@ public:
   Pointer() = default;
   Pointer(std::vector<std::variant<std::string, size_t>> const & tokens) : tokens_(tokens) {}
   Pointer(std::string_view path) {
+    if (path.empty()) {
+      return;
+    }
+
     auto append_with_parse = [this](std::string in) {
-      if (in.find_first_not_of("0123456789") == std::string::npos) {
-        tokens_.push_back(std::stoull(in));
-      } else {
-        tokens_.push_back(std::move(in));
+      if (not in.empty() && in.find_first_not_of("0123456789") == std::string::npos) {
+        return tokens_.push_back(std::stoull(in));
       }
+
+      for (size_t i = 0; i < in.size(); ++i) {
+        if (in[i] == '%') {
+          char const enc[3] = {in[i + 1], in[i + 2]};
+          in.replace(i, 3, 1, char(std::stoi(enc, nullptr, 16)));
+        } else if (in[i] != '~') {
+          continue;
+        }
+        if (in[i + 1] == '0') {
+          in.replace(i, 2, 1, '~');
+        } else if (in[i + 1] == '1') {
+          in.replace(i, 2, 1, '/');
+        }
+      }
+      tokens_.push_back(std::move(in));
     };
 
     path.remove_prefix(1);
@@ -31,9 +48,7 @@ public:
       append_with_parse(std::string(path.substr(0, p)));
     }
 
-    if (not path.empty()) {
-      append_with_parse(std::string(path));
-    }
+    append_with_parse(std::string(path));
   }
 
   template <Adapter A> A walk(A document) const {

+ 3 - 2
include/jvalidate/detail/reference.h

@@ -27,9 +27,10 @@ public:
     size_t const pointer_start = ref.find('/');
     anchor_ = Anchor(ref.substr(0, pointer_start));
     EXPECT_M(allow_anchor || anchor_.empty(), "Anchoring is not allowed in this context");
-    ref.remove_prefix(pointer_start);
 
-    pointer_ = ref;
+    if (pointer_start != std::string::npos) {
+      pointer_ = ref.substr(pointer_start);
+    }
   }
 
   URI const & uri() const { return uri_; }

+ 5 - 1
include/jvalidate/uri.h

@@ -17,13 +17,17 @@ public:
   URI() = default;
 
   explicit URI(std::string_view uri) : uri_(uri) {
-    if (uri_.back() == '#') {
+    if (not uri_.empty() && uri_.back() == '#') {
       uri_.pop_back();
     }
 
     if (size_t n = uri_.find("://"); n != std::string::npos) {
       scheme_ = n;
       resource_ = n + 3;
+    } else if (uri_.starts_with("urn:")) {
+      n = uri_.find(':', 4);
+      scheme_ = n;
+      resource_ = scheme_ + 1;
     }
   }