diff --git a/src/json-schema.hpp b/src/json-schema.hpp index 3137353..0211fbb 100644 --- a/src/json-schema.hpp +++ b/src/json-schema.hpp @@ -116,6 +116,12 @@ public: const std::string url() const; + // decode and encode strings for ~ and % escape sequences + static std::string unescape(const std::string &); + static std::string escape(const std::string &); + + // create a new json_uri based in this one and the given uri + // resolves relative changes (pathes or pointers) and resets part if proto or hostname changes json_uri derive(const std::string &uri) const { json_uri u = *this; @@ -123,6 +129,7 @@ public: return u; } + // append a pointer-field to the pointer-part of this uri json_uri append(const std::string &field) const { json_uri u = *this; @@ -145,7 +152,6 @@ public: friend std::ostream &operator<<(std::ostream &os, const json_uri &u); }; -// namespace json_schema_draft4 { diff --git a/src/json-uri.cpp b/src/json-uri.cpp index 72c88da..e480fce 100644 --- a/src/json-uri.cpp +++ b/src/json-uri.cpp @@ -25,7 +25,8 @@ */ #include "json-schema.hpp" -namespace nlohmann { +namespace nlohmann +{ void json_pointer::from_string(const std::string &r) { @@ -124,4 +125,63 @@ std::ostream &operator<<(std::ostream &os, const json_uri &u) return os << u.to_string(); } +std::string json_uri::unescape(const std::string &src) +{ + std::string l = src; + std::size_t pos = src.size() - 1; + + do { + pos = l.rfind('~', pos); + + if (pos == std::string::npos) + break; + + if (pos < l.size() - 1) { + switch (l[pos + 1]) { + case '0': + l.replace(pos, 2, "~"); + break; + + case '1': + l.replace(pos, 2, "/"); + break; + + default: + break; + } + } + + if (pos == 0) + break; + pos--; + } while (pos != std::string::npos); + + // TODO - percent handling + + return l; } + +std::string json_uri::escape(const std::string &src) +{ + std::vector> chars = { + {"~", "~0"}, + {"/", "~1"}, + {"%", "%25"}}; + + std::string l = src; + + for (const auto &c : chars) { + std::size_t pos = 0; + do { + pos = l.find(c.first, pos); + if (pos == std::string::npos) + break; + l.replace(pos, 1, c.second); + pos += c.second.size(); + } while (1); + } + + return l; +} + +} // nlohmann diff --git a/src/json-validator.cpp b/src/json-validator.cpp index 6e8752e..5f5d6fa 100644 --- a/src/json-validator.cpp +++ b/src/json-validator.cpp @@ -57,12 +57,12 @@ class resolver switch (i.value().type()) { case json::value_t::object: // child is object, it is a schema - resolve(i.value(), id.append(i.key())); + resolve(i.value(), id.append( json_uri::escape(i.key())) ); break; case json::value_t::array: { std::size_t index = 0; - auto child_id = id.append(i.key()); + auto child_id = id.append(json_uri::escape(i.key())); for (auto &v : i.value()) { if (v.type() == json::value_t::object) // array element is object resolve(v, child_id.append(std::to_string(index)) );