/* * Modern C++ JSON schema validator * * Licensed under the MIT License . * * Copyright (c) 2016 Patrick Boettcher . * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom * the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "json-schema.hpp" namespace nlohmann { void json_pointer::from_string(const std::string &r) { str_ = "#"; if (r.size() == 0) return; if (r[0] != '#') throw std::invalid_argument("not a valid JSON pointer - missing # at the beginning"); if (r.size() == 1) return; std::size_t pos = 1; do { std::size_t next = r.find('/', pos + 1); str_.append(r.substr(pos, next - pos)); pos = next; } while (pos != std::string::npos); } void json_uri::from_string(const std::string &uri) { // if it is an urn take it as it is - maybe there is more to be done if (uri.find("urn:") == 0) { urn_ = uri; return; } std::string pointer = "#"; // default pointer is the root // first split the URI into URL and JSON-pointer auto pointer_separator = uri.find('#'); if (pointer_separator != std::string::npos) // and extract the JSON-pointer-string if found pointer = uri.substr(pointer_separator); // the rest is an URL std::string url = uri.substr(0, pointer_separator); if (url.size()) { // if an URL is part of the URI std::size_t pos = 0; auto proto = url.find("://", pos); if (proto != std::string::npos) { // extract the protocol proto_ = url.substr(pos, proto - pos); pos = 3 + proto; // 3 == "://" auto hostname = url.find("/", pos); if (hostname != std::string::npos) { // and the hostname (no proto without hostname) hostname_ = url.substr(pos, hostname - pos); pos = hostname; } } // the rest is the path auto path = url.substr(pos); if (path[0] == '/') // if it starts with a / it is root-path path_ = path; else { // otherwise it is a subfolder // HACK(syoyo): Force append '/' for glTF json schemas path_ = path; //path_.append(path); } pointer_ = json_pointer(""); } if (pointer.size() > 0) pointer_ = pointer; } const std::string json_uri::url() const { std::stringstream s; if (proto_.size() > 0) s << proto_ << "://"; s << hostname_ << path_; return s.str(); } std::string json_uri::to_string() const { std::stringstream s; s << urn_ << url() << pointer_.to_string(); return s.str(); } 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