blob: 2dc6113ffea32b187ceb5715f7d12fb5413c6d25 [file] [log] [blame] [edit]
/*
* Modern C++ JSON schema validator
*
* Licensed under the MIT License <http://opensource.org/licenses/MIT>.
*
* Copyright (c) 2016 Patrick Boettcher <patrick.boettcher@posteo.de>.
*
* 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<std::pair<std::string, std::string>> 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