diff options
Diffstat (limited to '')
-rw-r--r-- | src/serialization/json_object.h | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/src/serialization/json_object.h b/src/serialization/json_object.h new file mode 100644 index 000000000..8e0da9aa5 --- /dev/null +++ b/src/serialization/json_object.h @@ -0,0 +1,344 @@ +// Copyright (c) 2016-2017, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#pragma once + +#include "rapidjson/document.h" +#include "cryptonote_basic/cryptonote_basic.h" +#include "rpc/message_data_structs.h" +#include "cryptonote_protocol/cryptonote_protocol_defs.h" +#include "common/sfinae_helpers.h" + +#define OBJECT_HAS_MEMBER_OR_THROW(val, key) \ + do \ + { \ + if (!val.HasMember(key)) \ + { \ + throw cryptonote::json::MISSING_KEY(key); \ + } \ + } while (0); + +#define INSERT_INTO_JSON_OBJECT(jsonVal, doc, key, source) \ + rapidjson::Value key##Val; \ + cryptonote::json::toJsonValue(doc, source, key##Val); \ + jsonVal.AddMember(#key, key##Val, doc.GetAllocator()); + +#define GET_FROM_JSON_OBJECT(source, dst, key) \ + OBJECT_HAS_MEMBER_OR_THROW(source, #key) \ + decltype(dst) dstVal##key; \ + cryptonote::json::fromJsonValue(source[#key], dstVal##key); \ + dst = dstVal##key; + +namespace cryptonote +{ + +namespace json +{ + +struct JSON_ERROR : public std::exception +{ + protected: + JSON_ERROR() { } + std::string m; + + public: + virtual ~JSON_ERROR() { } + + const char* what() const throw() + { + return m.c_str(); + } +}; + +struct MISSING_KEY : public JSON_ERROR +{ + MISSING_KEY(const char* key) + { + m = std::string("Key \"") + key + "\" missing from object."; + } +}; + +struct WRONG_TYPE : public JSON_ERROR +{ + WRONG_TYPE(const char* type) + { + m = std::string("Json value has incorrect type, expected: ") + type; + } +}; + +struct BAD_INPUT : public JSON_ERROR +{ + BAD_INPUT() + { + m = "An item failed to convert from json object to native object"; + } +}; + +struct PARSE_FAIL : public JSON_ERROR +{ + PARSE_FAIL() + { + m = "Failed to parse the json request"; + } +}; + + +// POD to json value +template <class Type> +typename std::enable_if<std::is_pod<Type>::value, void>::type toJsonValue(rapidjson::Document& doc, const Type& pod, rapidjson::Value& value) +{ + value = rapidjson::Value(epee::string_tools::pod_to_hex(pod).c_str(), doc.GetAllocator()); +} + +template <class Type> +typename std::enable_if<std::is_pod<Type>::value, void>::type fromJsonValue(const rapidjson::Value& val, Type& t) +{ + if (!val.IsString()) + { + throw WRONG_TYPE("string"); + } + + //TODO: handle failure to convert hex string to POD type + bool success = epee::string_tools::hex_to_pod(val.GetString(), t); + + if (!success) + { + throw BAD_INPUT(); + } +} + +void toJsonValue(rapidjson::Document& doc, const std::string& i, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, std::string& str); + +void toJsonValue(rapidjson::Document& doc, bool i, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, bool& b); + +void toJsonValue(rapidjson::Document& doc, const uint8_t& i, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, uint8_t& i); + +void toJsonValue(rapidjson::Document& doc, const int8_t& i, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, int8_t& i); + +void toJsonValue(rapidjson::Document& doc, const uint16_t& i, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, uint16_t& i); + +void toJsonValue(rapidjson::Document& doc, const int32_t& i, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, int32_t& i); + +void toJsonValue(rapidjson::Document& doc, const uint32_t& i, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, uint32_t& i); + +void toJsonValue(rapidjson::Document& doc, const uint64_t& i, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, uint64_t& i); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::transaction& tx, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::transaction& tx); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::block& b, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::block& b); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::txin_v& txin, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_v& txin); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::txin_gen& txin, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_gen& txin); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::txin_to_script& txin, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_to_script& txin); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::txin_to_scripthash& txin, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_to_scripthash& txin); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::txin_to_key& txin, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_to_key& txin); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::txout_target_v& txout, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_target_v& txout); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::txout_to_script& txout, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_to_script& txout); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::txout_to_scripthash& txout, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_to_scripthash& txout); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::txout_to_key& txout, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_to_key& txout); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::tx_out& txout, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::tx_out& txout); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::connection_info& info, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::connection_info& info); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::block_complete_entry& blk, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::block_complete_entry& blk); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::block_with_transactions& blk, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::block_with_transactions& blk); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::transaction_info& tx_info, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::transaction_info& tx_info); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::output_key_and_amount_index& out, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_key_and_amount_index& out); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::amount_with_random_outputs& out, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::amount_with_random_outputs& out); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::peer& peer, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::peer& peer); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::tx_in_pool& tx, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::tx_in_pool& tx); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::hard_fork_info& info, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::hard_fork_info& info); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::output_amount_count& out, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_amount_count& out); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::output_amount_and_index& out, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_amount_and_index& out); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::output_key_mask_unlocked& out, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_key_mask_unlocked& out); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::error& err, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::error& error); + +void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::BlockHeaderResponse& response, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::BlockHeaderResponse& response); + +void toJsonValue(rapidjson::Document& doc, const rct::rctSig& i, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& i, rct::rctSig& sig); + +void toJsonValue(rapidjson::Document& doc, const rct::ctkey& key, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, rct::ctkey& key); + +void toJsonValue(rapidjson::Document& doc, const rct::ecdhTuple& tuple, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, rct::ecdhTuple& tuple); + +void toJsonValue(rapidjson::Document& doc, const rct::rctSigPrunable& sig, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, rct::rctSigPrunable& sig); + +void toJsonValue(rapidjson::Document& doc, const rct::rangeSig& sig, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, rct::rangeSig& sig); + +void toJsonValue(rapidjson::Document& doc, const rct::boroSig& sig, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, rct::boroSig& sig); + +void toJsonValue(rapidjson::Document& doc, const rct::mgSig& sig, rapidjson::Value& val); +void fromJsonValue(const rapidjson::Value& val, rct::mgSig& sig); + + +template <typename Map> +typename std::enable_if<sfinae::is_map_like<Map>::value, void>::type toJsonValue(rapidjson::Document& doc, const Map& map, rapidjson::Value& val); + +template <typename Map> +typename std::enable_if<sfinae::is_map_like<Map>::value, void>::type fromJsonValue(const rapidjson::Value& val, Map& map); + +template <typename Vec> +typename std::enable_if<sfinae::is_vector_like<Vec>::value, void>::type toJsonValue(rapidjson::Document& doc, const Vec &vec, rapidjson::Value& val); + +template <typename Vec> +typename std::enable_if<sfinae::is_vector_like<Vec>::value, void>::type fromJsonValue(const rapidjson::Value& val, Vec& vec); + + +// ideally would like to have the below functions in the .cpp file, but +// unfortunately because of how templates work they have to be here. + +template <typename Map> +typename std::enable_if<sfinae::is_map_like<Map>::value, void>::type toJsonValue(rapidjson::Document& doc, const Map& map, rapidjson::Value& val) +{ + val.SetObject(); + + auto& al = doc.GetAllocator(); + + for (const auto& i : map) + { + rapidjson::Value k; + rapidjson::Value m; + toJsonValue(doc, i.first, k); + toJsonValue(doc, i.second, m); + val.AddMember(k, m, al); + } +} + +template <typename Map> +typename std::enable_if<sfinae::is_map_like<Map>::value, void>::type fromJsonValue(const rapidjson::Value& val, Map& map) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + auto itr = val.MemberBegin(); + + while (itr != val.MemberEnd()) + { + typename Map::key_type k; + typename Map::mapped_type m; + fromJsonValue(itr->name, k); + fromJsonValue(itr->value, m); + map.emplace(k, m); + ++itr; + } +} + +template <typename Vec> +typename std::enable_if<sfinae::is_vector_like<Vec>::value, void>::type toJsonValue(rapidjson::Document& doc, const Vec &vec, rapidjson::Value& val) +{ + val.SetArray(); + + for (const auto& t : vec) + { + rapidjson::Value v; + toJsonValue(doc, t, v); + val.PushBack(v, doc.GetAllocator()); + } +} + +template <typename Vec> +typename std::enable_if<sfinae::is_vector_like<Vec>::value, void>::type fromJsonValue(const rapidjson::Value& val, Vec& vec) +{ + if (!val.IsArray()) + { + throw WRONG_TYPE("json array"); + } + + for (rapidjson::SizeType i=0; i < val.Size(); i++) + { + typename Vec::value_type v; + fromJsonValue(val[i], v); + vec.push_back(v); + } +} + +} // namespace json + +} // namespace cryptonote |