From 483eb198fdf4912b2c9ebc9d27d623c3103fef2d Mon Sep 17 00:00:00 2001 From: altalk23 <45172705+altalk23@users.noreply.github.com> Date: Sun, 23 Oct 2022 16:22:27 +0300 Subject: [PATCH] add json validation to source --- .../include/Geode/loader/platform/macos.hpp | 3 - loader/include/Geode/utils/JsonValidation.hpp | 181 ++------- loader/src/utils/JsonValidation.cpp | 366 ++++++++++++++++++ 3 files changed, 401 insertions(+), 149 deletions(-) create mode 100644 loader/src/utils/JsonValidation.cpp diff --git a/loader/include/Geode/loader/platform/macos.hpp b/loader/include/Geode/loader/platform/macos.hpp index ebda5a6f..3757afbe 100644 --- a/loader/include/Geode/loader/platform/macos.hpp +++ b/loader/include/Geode/loader/platform/macos.hpp @@ -1,8 +1,5 @@ #pragma once -#define GEODE_API extern "C" -#define GEODE_DLL - namespace geode { using dylib_t = void*; struct PlatformInfo { diff --git a/loader/include/Geode/utils/JsonValidation.hpp b/loader/include/Geode/utils/JsonValidation.hpp index 6747ae01..bd0c5773 100644 --- a/loader/include/Geode/utils/JsonValidation.hpp +++ b/loader/include/Geode/utils/JsonValidation.hpp @@ -104,47 +104,38 @@ namespace geode { friend struct JsonMaybeObject; friend struct JsonMaybeValue; - void setError(std::string const& error); + GEODE_DLL void setError(std::string const& error); public: - Json& json() { - return m_json; - } + GEODE_DLL Json& json(); - JsonMaybeSomething( + GEODE_DLL JsonMaybeSomething( JsonChecker& checker, Json& json, std::string const& hierarchy, bool hasValue - ) : m_checker(checker), - m_json(json), - m_hierarchy(hierarchy), - m_hasValue(hasValue) {} + ); - bool isError() const; + GEODE_DLL bool isError() const; - operator bool() const { - return !isError(); - } + GEODE_DLL operator bool() const; }; template struct JsonMaybeValue : public JsonMaybeSomething { bool m_inferType = true; - JsonMaybeValue( + GEODE_DLL JsonMaybeValue( JsonChecker& checker, Json& json, std::string const& hierarchy, bool hasValue - ) : JsonMaybeSomething(checker, json, hierarchy, hasValue) {} + ); - JsonMaybeSomething& self() { - return *static_cast*>(this); - } + GEODE_DLL JsonMaybeSomething& self(); template - JsonMaybeValue as() { + JsonMaybeValue& as() { if (this->isError()) return *this; if (!jsonConvertibleTo(self().m_json.type(), T)) { this->setError( @@ -157,13 +148,10 @@ namespace geode { return *this; } - JsonMaybeValue array() { - this->as(); - return *this; - } + GEODE_DLL JsonMaybeValue& array(); template - JsonMaybeValue asOneOf() { + JsonMaybeValue& asOneOf() { if (this->isError()) return *this; bool isOneOf = (... || jsonConvertibleTo(self().m_json.type(), T)); if (!isOneOf) { @@ -178,7 +166,7 @@ namespace geode { } template - JsonMaybeValue is() { + JsonMaybeValue& is() { if (this->isError()) return *this; self().m_hasValue = jsonConvertibleTo(self().m_json.type(), T); m_inferType = false; @@ -186,7 +174,7 @@ namespace geode { } template - JsonMaybeValue validate(JsonValueValidator validator) { + JsonMaybeValue& validate(JsonValueValidator validator) { if (this->isError()) return *this; try { if (!validator(self().m_json.template get())) { @@ -202,30 +190,30 @@ namespace geode { } template - JsonMaybeValue inferType() { + JsonMaybeValue& inferType() { if (this->isError() || !m_inferType) return *this; return this->as()>(); } template - JsonMaybeValue intoRaw(T& target) { + JsonMaybeValue& intoRaw(T& target) { if (this->isError()) return *this; target = self().m_json; return *this; } template - JsonMaybeValue into(T& target) { + JsonMaybeValue& into(T& target) { return this->intoAs(target); } template - JsonMaybeValue into(std::optional& target) { + JsonMaybeValue& into(std::optional& target) { return this->intoAs>(target); } template - JsonMaybeValue intoAs(T& target) { + JsonMaybeValue& intoAs(T& target) { this->inferType(); if (this->isError()) return *this; try { @@ -278,112 +266,37 @@ namespace geode { } }; - JsonMaybeValue at(size_t i) { - this->as(); - if (this->isError()) return *this; - if (self().m_json.size() <= i) { - this->setError( - self().m_hierarchy + ": has " + - std::to_string(self().m_json.size()) + "items " - ", expected to have at least " + std::to_string(i + 1) - ); - return *this; - } - return JsonMaybeValue( - self().m_checker, self().m_json.at(i), - self().m_hierarchy + "." + std::to_string(i), - self().m_hasValue - ); - } + GEODE_DLL JsonMaybeValue at(size_t i); - Iterator> iterate() { - this->as(); - Iterator> iter; - if (this->isError()) return iter; - size_t i = 0; - for (auto& obj : self().m_json) { - iter.m_values.emplace_back( - self().m_checker, obj, - self().m_hierarchy + "." + std::to_string(i++), - self().m_hasValue - ); - } - return iter; - } + GEODE_DLL Iterator> iterate(); - Iterator>> items() { - this->as(); - Iterator>> iter; - if (this->isError()) return iter; - - for (auto& [k, v] : self().m_json.items()) { - iter.m_values.emplace_back(k, JsonMaybeValue( - self().m_checker, v, - self().m_hierarchy + "." + k, - self().m_hasValue - )); - } - - return iter; - } + GEODE_DLL Iterator>> items(); }; template struct JsonMaybeObject : JsonMaybeSomething { std::set m_knownKeys; - JsonMaybeObject( + GEODE_DLL JsonMaybeObject( JsonChecker& checker, Json& json, std::string const& hierarchy, bool hasValue - ) : JsonMaybeSomething(checker, json, hierarchy, hasValue) {} + ); - JsonMaybeSomething& self() { - return *static_cast*>(this); - } + GEODE_DLL JsonMaybeSomething& self(); - void addKnownKey(std::string const& key) { - m_knownKeys.insert(key); - } + GEODE_DLL void addKnownKey(std::string const& key); - Json& json() { - return self().m_json; - } + GEODE_DLL Json& json(); - JsonMaybeValue emptyValue() { - return JsonMaybeValue(self().m_checker, self().m_json, "", false); - } + GEODE_DLL JsonMaybeValue emptyValue(); - JsonMaybeValue has(std::string const& key) { - this->addKnownKey(key); - if (this->isError()) return emptyValue(); - if (!self().m_json.contains(key) || self().m_json[key].is_null()) { - return emptyValue(); - } - return JsonMaybeValue(self().m_checker, self().m_json[key], key, true); - } + GEODE_DLL JsonMaybeValue has(std::string const& key); - JsonMaybeValue needs(std::string const& key) { - this->addKnownKey(key); - if (this->isError()) return emptyValue(); - if (!self().m_json.contains(key)) { - this->setError( - self().m_hierarchy + " is missing required key \"" + key + "\"" - ); - return emptyValue(); - } - return JsonMaybeValue(self().m_checker, self().m_json[key], key, true); - } + GEODE_DLL JsonMaybeValue needs(std::string const& key); - void checkUnknownKeys() { - for (auto& [key, _] : self().m_json.items()) { - if (!m_knownKeys.count(key)) { - // log::debug(self().m_hierarchy + " contains unknown key \"" + key + "\""); - log::debug("{} contains unknown key \"{}\"", self().m_hierarchy, key); - } - } - } + GEODE_DLL void checkUnknownKeys(); }; template @@ -391,37 +304,13 @@ namespace geode { std::variant m_result; Json& m_json; - JsonChecker(Json& json) : m_json(json), m_result(std::monostate()) {} + GEODE_DLL JsonChecker(Json& json); - bool isError() const { - return std::holds_alternative(m_result); - } + GEODE_DLL bool isError() const; - std::string getError() const { - return std::get(m_result); - } + GEODE_DLL std::string getError() const; - JsonMaybeValue root(std::string const& hierarchy) { - return JsonMaybeValue(*this, m_json, hierarchy, true); - } + GEODE_DLL JsonMaybeValue root(std::string const& hierarchy); }; - template - void JsonMaybeSomething::setError(std::string const& error) { - m_checker.m_result = error; - } - - template - bool JsonMaybeSomething::isError() const { - return m_checker.isError() || !m_hasValue; - } - - template - JsonMaybeObject JsonMaybeValue::obj() { - this->as(); - return JsonMaybeObject( - self().m_checker, self().m_json, - self().m_hierarchy, self().m_hasValue - ); - } } diff --git a/loader/src/utils/JsonValidation.cpp b/loader/src/utils/JsonValidation.cpp new file mode 100644 index 00000000..f15caa0b --- /dev/null +++ b/loader/src/utils/JsonValidation.cpp @@ -0,0 +1,366 @@ +#include + +USE_GEODE_NAMESPACE(); + +template +Json& JsonMaybeSomething::json() { + return m_json; +} + +template +JsonMaybeSomething::JsonMaybeSomething( + JsonChecker& checker, + Json& json, + std::string const& hierarchy, + bool hasValue +) : m_checker(checker), + m_json(json), + m_hierarchy(hierarchy), + m_hasValue(hasValue) {} + +template +bool JsonMaybeSomething::isError() const { + return m_checker.isError() || !m_hasValue; +} + +template +JsonMaybeSomething::operator bool() const { + return !isError(); +} + +template +void JsonMaybeSomething::setError(std::string const& error) { + m_checker.m_result = error; +} + +template +JsonMaybeValue::JsonMaybeValue( + JsonChecker& checker, + Json& json, + std::string const& hierarchy, + bool hasValue +) : JsonMaybeSomething(checker, json, hierarchy, hasValue) {} + +template +JsonMaybeSomething& JsonMaybeValue::self() { + return *static_cast*>(this); +} + +// template +// template +// JsonMaybeValue& JsonMaybeValue::as() { +// if (this->isError()) return *this; +// if (!jsonConvertibleTo(self().m_json.type(), T)) { +// this->setError( +// self().m_hierarchy + ": Invalid type \"" + +// self().m_json.type_name() + "\", expected \"" + +// jsonValueTypeToString(T) + "\"" +// ); +// } +// m_inferType = false; +// return *this; +// } + +template +JsonMaybeValue& JsonMaybeValue::array() { + this->as(); + return *this; +} + + +// template +// template +// JsonMaybeValue JsonMaybeValue::asOneOf() { +// if (this->isError()) return *this; +// bool isOneOf = (... || jsonConvertibleTo(self().m_json.type(), T)); +// if (!isOneOf) { +// this->setError( +// self().m_hierarchy + ": Invalid type \"" + +// self().m_json.type_name() + "\", expected one of \"" + +// (jsonValueTypeToString(T), ...) + "\"" +// ); +// } +// m_inferType = false; +// return *this; +// } + + +// template +// template +// JsonMaybeValue JsonMaybeValue::is() { +// if (this->isError()) return *this; +// self().m_hasValue = jsonConvertibleTo(self().m_json.type(), T); +// m_inferType = false; +// return *this; +// } + + +// template +// template +// JsonMaybeValue JsonMaybeValue::validate(JsonValueValidator validator) { +// if (this->isError()) return *this; +// try { +// if (!validator(self().m_json.template get())) { +// this->setError(self().m_hierarchy + ": Invalid value format"); +// } +// } catch(...) { +// this->setError( +// self().m_hierarchy + ": Invalid type \"" + +// std::string(self().m_json.type_name()) + "\"" +// ); +// } +// return *this; +// } + + +// template +// template +// JsonMaybeValue JsonMaybeValue::inferType() { +// if (this->isError() || !m_inferType) return *this; +// return this->as()>(); +// } + + +// template +// template +// JsonMaybeValue JsonMaybeValue::intoRaw(T& target) { +// if (this->isError()) return *this; +// target = self().m_json; +// return *this; +// } + + +// template +// template +// JsonMaybeValue JsonMaybeValue::into(T& target) { +// return this->intoAs(target); +// } + + +// template +// template +// JsonMaybeValue JsonMaybeValue::into(std::optional& target) { +// return this->intoAs>(target); +// } + + +// template +// template +// JsonMaybeValue JsonMaybeValue::intoAs(T& target) { +// this->inferType(); +// if (this->isError()) return *this; +// try { +// target = self().m_json.template get(); +// } catch(...) { +// this->setError( +// self().m_hierarchy + ": Invalid type \"" + +// std::string(self().m_json.type_name()) + "\"" +// ); +// } +// return *this; +// } + +// template +// template +// T JsonMaybeValue::get() { +// this->inferType(); +// if (this->isError()) return T(); +// try { +// return self().m_json.template get(); +// } catch(...) { +// this->setError( +// self().m_hierarchy + ": Invalid type to get \"" + +// std::string(self().m_json.type_name()) + "\"" +// ); +// } +// return T(); +// } + +template +JsonMaybeObject JsonMaybeValue::obj() { + this->as(); + return JsonMaybeObject( + self().m_checker, self().m_json, + self().m_hierarchy, self().m_hasValue + ); +} + +// template +// template +// struct JsonMaybeValue::Iterator { +// std::vector m_values; + +// using iterator = typename std::vector::iterator; +// using const_iterator = typename std::vector::const_iterator; + +// iterator begin() { +// return m_values.begin(); +// } +// iterator end() { +// return m_values.end(); +// } + +// const_iterator begin() const { +// return m_values.begin(); +// } +// const_iterator end() const { +// return m_values.end(); +// } +// }; + +template +JsonMaybeValue JsonMaybeValue::at(size_t i) { + this->as(); + if (this->isError()) return *this; + if (self().m_json.size() <= i) { + this->setError( + self().m_hierarchy + ": has " + + std::to_string(self().m_json.size()) + "items " + ", expected to have at least " + std::to_string(i + 1) + ); + return *this; + } + return JsonMaybeValue( + self().m_checker, self().m_json.at(i), + self().m_hierarchy + "." + std::to_string(i), + self().m_hasValue + ); +} + +template +typename JsonMaybeValue::template Iterator> JsonMaybeValue::iterate() { + this->as(); + Iterator> iter; + if (this->isError()) return iter; + size_t i = 0; + for (auto& obj : self().m_json) { + iter.m_values.emplace_back( + self().m_checker, obj, + self().m_hierarchy + "." + std::to_string(i++), + self().m_hasValue + ); + } + return iter; +} + +template +typename JsonMaybeValue::template Iterator>> JsonMaybeValue::items() { + this->as(); + Iterator>> iter; + if (this->isError()) return iter; + + for (auto& [k, v] : self().m_json.items()) { + iter.m_values.emplace_back(k, JsonMaybeValue( + self().m_checker, v, + self().m_hierarchy + "." + k, + self().m_hasValue + )); + } + + return iter; +} + + +template +JsonMaybeObject::JsonMaybeObject( + JsonChecker& checker, + Json& json, + std::string const& hierarchy, + bool hasValue +) : JsonMaybeSomething(checker, json, hierarchy, hasValue) {} + +template +JsonMaybeSomething& JsonMaybeObject::self() { + return *static_cast*>(this); +} + +template +void JsonMaybeObject::addKnownKey(std::string const& key) { + m_knownKeys.insert(key); +} + +template +Json& JsonMaybeObject::json() { + return self().m_json; +} + +template +JsonMaybeValue JsonMaybeObject::emptyValue() { + return JsonMaybeValue(self().m_checker, self().m_json, "", false); +} + +template +JsonMaybeValue JsonMaybeObject::has(std::string const& key) { + this->addKnownKey(key); + if (this->isError()) return emptyValue(); + if (!self().m_json.contains(key) || self().m_json[key].is_null()) { + return emptyValue(); + } + return JsonMaybeValue(self().m_checker, self().m_json[key], key, true); +} + +template +JsonMaybeValue JsonMaybeObject::needs(std::string const& key) { + this->addKnownKey(key); + if (this->isError()) return emptyValue(); + if (!self().m_json.contains(key)) { + this->setError( + self().m_hierarchy + " is missing required key \"" + key + "\"" + ); + return emptyValue(); + } + return JsonMaybeValue(self().m_checker, self().m_json[key], key, true); +} + +template +void JsonMaybeObject::checkUnknownKeys() { + for (auto& [key, _] : self().m_json.items()) { + if (!m_knownKeys.count(key)) { + // log::debug(self().m_hierarchy + " contains unknown key \"" + key + "\""); + log::debug("{} contains unknown key \"{}\"", self().m_hierarchy, key); + } + } +} + +template +JsonChecker::JsonChecker(Json& json) : m_json(json), m_result(std::monostate()) {} + +template +bool JsonChecker::isError() const { + return std::holds_alternative(m_result); +} + +template +std::string JsonChecker::getError() const { + return std::get(m_result); +} + +template +JsonMaybeValue JsonChecker::root(std::string const& hierarchy) { + return JsonMaybeValue(*this, m_json, hierarchy, true); +} + + + +namespace geode { + + template struct JsonMaybeSomething; + template struct JsonMaybeSomething; + template struct JsonMaybeSomething; + + + template struct JsonMaybeValue; + template struct JsonMaybeValue; + template struct JsonMaybeValue; + + + template struct JsonMaybeObject; + template struct JsonMaybeObject; + template struct JsonMaybeObject; + + + template struct JsonChecker; + template struct JsonChecker; + template struct JsonChecker; + +} \ No newline at end of file